-
Notifications
You must be signed in to change notification settings - Fork 0
TMP: include changes for BIMv2 in BIMv1to compare changes #1
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,6 +43,15 @@ contract BasicIssuanceModule is ModuleBase, ReentrancyGuard { | |
using SafeMath for uint256; | ||
using SafeCast for int256; | ||
|
||
/* ============ Structs ============ */ | ||
|
||
// NOTE: moduleIssuanceHooks uses address[] for compatibility with AddressArrayUtils library | ||
struct IssuanceSettings { | ||
IManagerIssuanceHook managerIssuanceHook; // Instance of manager defined hook, can hold arbitrary logic | ||
address[] moduleIssuanceHooks; // Array of modules that are registered with this module | ||
mapping(address => bool) isModuleHook; // Mapping of modules to if they've registered a hook | ||
} | ||
|
||
/* ============ Events ============ */ | ||
|
||
event SetTokenIssued( | ||
|
@@ -56,13 +65,13 @@ contract BasicIssuanceModule is ModuleBase, ReentrancyGuard { | |
address indexed _setToken, | ||
address indexed _redeemer, | ||
address indexed _to, | ||
address _hookContract, | ||
uint256 _quantity | ||
); | ||
|
||
/* ============ State Variables ============ */ | ||
|
||
// Mapping of SetToken to Issuance hook configurations | ||
mapping(ISetToken => IManagerIssuanceHook) public managerIssuanceHook; | ||
mapping(ISetToken => IssuanceSettings) public issuanceSettings; | ||
|
||
/* ============ Constructor ============ */ | ||
|
||
|
@@ -94,7 +103,9 @@ contract BasicIssuanceModule is ModuleBase, ReentrancyGuard { | |
{ | ||
require(_quantity > 0, "Issue quantity must be > 0"); | ||
|
||
address hookContract = _callPreIssueHooks(_setToken, _quantity, msg.sender, _to); | ||
address hookContract = _callManagerPreIssueHooks(_setToken, _quantity, msg.sender, _to); | ||
|
||
_callModulePreIssueHooks(_setToken, _quantity); | ||
|
||
( | ||
address[] memory components, | ||
|
@@ -118,7 +129,7 @@ contract BasicIssuanceModule is ModuleBase, ReentrancyGuard { | |
emit SetTokenIssued(address(_setToken), msg.sender, _to, hookContract, _quantity); | ||
} | ||
|
||
/** | ||
/** | ||
* Redeems the SetToken's positions and sends the components of the given | ||
* quantity to the caller. This function only handles Default Positions (positionState = 0). | ||
* | ||
|
@@ -132,11 +143,16 @@ contract BasicIssuanceModule is ModuleBase, ReentrancyGuard { | |
address _to | ||
) | ||
external | ||
override | ||
nonReentrant | ||
onlyValidAndInitializedSet(_setToken) | ||
{ | ||
require(_quantity > 0, "Redeem quantity must be > 0"); | ||
|
||
address hookContract = _callManagerPreRedeemHooks(_setToken, _quantity, msg.sender, _to); | ||
|
||
_callModulePreRedeemHooks(_setToken, _quantity); | ||
|
||
// Burn the SetToken - ERC20's internal burn already checks that the user has enough balance | ||
_setToken.burn(msg.sender, _quantity); | ||
|
||
|
@@ -159,7 +175,7 @@ contract BasicIssuanceModule is ModuleBase, ReentrancyGuard { | |
); | ||
} | ||
|
||
emit SetTokenRedeemed(address(_setToken), msg.sender, _to, _quantity); | ||
emit SetTokenRedeemed(address(_setToken), msg.sender, _to, hookContract, _quantity); | ||
} | ||
|
||
/** | ||
|
@@ -183,11 +199,37 @@ contract BasicIssuanceModule is ModuleBase, ReentrancyGuard { | |
} | ||
|
||
/** | ||
* Reverts as this module should not be removable after added. Users should always | ||
* have a way to redeem their Sets | ||
* SET TOKEN ONLY: Allows removal (and deletion of state) of BasicIssuanceModuleV2 | ||
*/ | ||
function removeModule() external override { | ||
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. This method is not protected right ? So anyone can call it ? 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. Nevermind / False alarm: I just figured out that the method would fail if the caller is not a set token 👍 |
||
revert("The BasicIssuanceModule module cannot be removed"); | ||
require(issuanceSettings[ISetToken(msg.sender)].moduleIssuanceHooks.length == 0, "Registered modules must be removed."); | ||
delete issuanceSettings[ISetToken(msg.sender)]; | ||
} | ||
|
||
/** | ||
* MANAGER ONLY: Updates the address of the manager issuance hook. To remove the hook | ||
* set the new hook address to address(0) | ||
* | ||
* @param _setToken Instance of the SetToken to update manager hook | ||
* @param _newHook New manager hook contract address | ||
*/ | ||
function updateManagerIssuanceHook( | ||
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. this functionality is new. Not sure if really needed. Could be excluded because we have module hooks? 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. We do use the |
||
ISetToken _setToken, | ||
IManagerIssuanceHook _newHook | ||
) | ||
external | ||
onlySetManager(_setToken, msg.sender) | ||
onlyValidAndInitializedSet(_setToken) | ||
{ | ||
managerIssuanceHook[_setToken] = _newHook; | ||
} | ||
|
||
function getModuleIssuanceHooks(ISetToken _setToken) external view returns(address[] memory) { | ||
return issuanceSettings[_setToken].moduleIssuanceHooks; | ||
} | ||
|
||
function isModuleIssuanceHook(ISetToken _setToken, address _hook) external view returns(bool) { | ||
return issuanceSettings[_setToken].isModuleHook[_hook]; | ||
} | ||
|
||
/* ============ External Getter Functions ============ */ | ||
|
@@ -200,35 +242,70 @@ contract BasicIssuanceModule is ModuleBase, ReentrancyGuard { | |
* @return address[] List of component addresses | ||
* @return uint256[] List of component units required to issue the quantity of SetTokens | ||
*/ | ||
function getRequiredComponentUnitsForIssue( | ||
function getRequiredComponentIssuanceUnits( | ||
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. This is nice. Having different names for this method between BIM and DIM was really annoying before :+1 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. just noticed that they also differ in returned values... |
||
ISetToken _setToken, | ||
uint256 _quantity | ||
) | ||
public | ||
view | ||
onlyValidAndInitializedSet(_setToken) | ||
returns (address[] memory, uint256[] memory) | ||
{ | ||
return _calculateRequiredComponentIssuanceUnits(_setToken, totalQuantity, true); | ||
} | ||
|
||
/** | ||
* Calculates the amount of each component will be returned on redemption. | ||
* redeem Values DO NOT take into account any updates from pre action manager or module hooks. | ||
* | ||
* @param _setToken Instance of the SetToken to redeem | ||
* @param _quantity Amount of Sets to be redeemed | ||
* | ||
* @return address[] Array of component addresses making up the Set | ||
* @return uint256[] Array of equity notional amounts of each component, respectively, represented as uint256 | ||
*/ | ||
function getRequiredComponentRedemptionUnits( | ||
ISetToken _setToken, | ||
uint256 _quantity | ||
) | ||
external | ||
view | ||
virtual | ||
returns (address[] memory, uint256[] memory) | ||
{ | ||
return _calculateRequiredComponentIssuanceUnits(_setToken, totalQuantity, false); | ||
} | ||
|
||
/* ============ Internal Functions ============ */ | ||
|
||
function _calculateRequiredComponentIssuanceUnit ( | ||
ISetToken _setToken, | ||
uint256 _quantity, | ||
bool _isIssue | ||
) | ||
internal | ||
returns (address[] memory, uint256[] memory) | ||
{ | ||
address[] memory components = _setToken.getComponents(); | ||
|
||
uint256[] memory notionalUnits = new uint256[](components.length); | ||
|
||
for (uint256 i = 0; i < components.length; i++) { | ||
require(!_setToken.hasExternalPosition(components[i]), "Only default positions are supported"); | ||
|
||
notionalUnits[i] = _setToken.getDefaultPositionRealUnit(components[i]).toUint256().preciseMulCeil(_quantity); | ||
uint256 units = _setToken.getDefaultPositionRealUnit(components[i]).toUint256(); | ||
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. not exactly as in DIM, but almost |
||
notionalUnits[i] = _isIssue ? | ||
units.preciseMulCeil(_quantity) : | ||
units.preciseMul(_quantity); | ||
} | ||
|
||
return (components, notionalUnits); | ||
} | ||
|
||
/* ============ Internal Functions ============ */ | ||
|
||
/** | ||
* If a pre-issue hook has been configured, call the external-protocol contract. Pre-issue hook logic | ||
* can contain arbitrary logic including validations, external function calls, etc. | ||
*/ | ||
function _callPreIssueHooks( | ||
function _callManagerPreIssueHooks( | ||
ISetToken _setToken, | ||
uint256 _quantity, | ||
address _caller, | ||
|
@@ -237,12 +314,54 @@ contract BasicIssuanceModule is ModuleBase, ReentrancyGuard { | |
internal | ||
returns(address) | ||
{ | ||
IManagerIssuanceHook preIssueHook = managerIssuanceHook[_setToken]; | ||
IManagerIssuanceHook preIssueHook = issuanceSettings[_setToken].managerIssuanceHook; | ||
if (address(preIssueHook) != address(0)) { | ||
preIssueHook.invokePreIssueHook(_setToken, _quantity, _caller, _to); | ||
return address(preIssueHook); | ||
} | ||
|
||
return address(0); | ||
} | ||
|
||
/** | ||
* If a pre-redeem hook has been configured, call the external-protocol contract's pre-redeem function. | ||
* Pre-issue hook logic can contain arbitrary logic including validations, external function calls, etc. | ||
*/ | ||
function _callManagerPreRedeemHooks( | ||
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. again, DIM doesn't call manager pre redeem hooks |
||
ISetToken _setToken, | ||
uint256 _quantity, | ||
address _caller, | ||
address _to | ||
) | ||
internal | ||
returns(address) | ||
{ | ||
IManagerIssuanceHook preIssueHook = issuanceSettings[_setToken].managerIssuanceHook; | ||
if (address(preIssueHook) != address(0)) { | ||
preIssueHook.invokePreRedeemHook(_setToken, _quantity, _caller, _to); | ||
return address(preIssueHook); | ||
} | ||
|
||
return address(0); | ||
} | ||
|
||
/** | ||
* Calls all modules that have registered with the DebtIssuanceModule that have a moduleIssueHook. | ||
*/ | ||
function _callModulePreIssueHooks(ISetToken _setToken, uint256 _quantity) internal { | ||
address[] memory issuanceHooks = issuanceSettings[_setToken].moduleIssuanceHooks; | ||
for (uint256 i = 0; i < issuanceHooks.length; i++) { | ||
IModuleIssuanceHook(issuanceHooks[i]).moduleIssueHook(_setToken, _quantity); | ||
} | ||
} | ||
|
||
/** | ||
* Calls all modules that have registered with the DebtIssuanceModule that have a moduleRedeemHook. | ||
*/ | ||
function _callModulePreRedeemHooks(ISetToken _setToken, uint256 _quantity) internal { | ||
address[] memory issuanceHooks = issuanceSettings[_setToken].moduleIssuanceHooks; | ||
for (uint256 i = 0; i < issuanceHooks.length; i++) { | ||
IModuleIssuanceHook(issuanceHooks[i]).moduleRedeemHook(_setToken, _quantity); | ||
} | ||
} | ||
} |
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.
DIM doesn't have manager pre redeem hooks. not sure if we need that even if we add module hooks.
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.
Yeah, since neither DIM nor BIMv1 have this, I guess it wouldn't be needed. The only example of managerHooks I found in our tests is the max supply hook (see here) which only needs to be called at issuance.