-
Notifications
You must be signed in to change notification settings - Fork 53
Add Manager permissions for protected modules and extensions #71
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
Conversation
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.
Couple logic things I think we wanna clean up and then let's try to xfer everything to Extension terminology at this point, have a feeling we'll be using this new manager going forward (hence wanna have it in a new file).
One note that may be good to add is that Extensions can be added through:
addAdapter (Extension)
protectModule
replaceProtectedModule
emergencyReplaceProtectedModule
authorizeAdapter (Extension...and if we make the logic update I proposed)
Extensions can be removed (from adapters
array):
removeAdapter (Extension)
Extensions can be authorized:
protectModule
replaceProtectedModule
emergencyReplaceProtectedModule
authorizeAdapter (Extension...and if we make the logic update I proposed)
Extensions can be deauthorized:
replaceProtectedModule
emergencyRemoveProtectedModule
unProtectModule
Want to make sure that's your understanding as well. Think it's important to have those mapped out, that's the part I found the most confusing about it is the different Extension states.
|
||
|
||
/** | ||
* @title FeeSplitAdapter |
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.
Ah let's take this opportunity to rename the all the leftover "adapters" to "extensions"
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.
streamingFeeModule.accrueFee(setToken); | ||
|
||
uint256 totalFees = setToken.balanceOf(address(manager)); |
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.
To ensure that all fees can't be poached we actually want to send fees to this extension now. So we should be reading the balance on this contract
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.
This change is in feaf6a2.
This approach requires that any time a fee extension contract is added or replaced the fee recipient is updated (by mutual upgrade) as well.
Have added a distribute
method to the extensions that lets distribution happen whether the extension is authorized or not. This might be necessary if accrue
is called on the streaming fee module during a transition from one extension to another, or fees went undistributed for other reasons.
[EDIT - distribute is unnecessary because there's no routing through the manager. Have added a behavioral test that makes sure we can sweep accrued fees from a de-authorized and removed extension since this is something that might be necessary]
contracts/manager/BaseManager.sol
Outdated
*/ | ||
|
||
pragma solidity 0.6.10; | ||
pragma experimental ABIEncoderV2; |
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.
Sorry I should have clarified this...I think there's enough changes here that it warrants a different manager contract. I want to preserve the old contract so maybe we make this PermissionedManager
or something to that affect. There's probably a better name...
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.
Also given we're trying to move towards the Extension nomenclature and we're changing a lot about this BaseManager can we change the adapter
to extension
. I should have specified that in the spec, that's my bad.
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.
Ah, I overlooked the suggestion to rename the manager descriptively and did V2
.....
contracts/manager/BaseManager.sol
Outdated
* OPERATOR ONLY: Marks a currently protected module as unprotected and deletes its authorized | ||
* adapter registries. Removes module from the SetToken. Increments the `emergencies` counter, | ||
* prohibiting any operator-only module or extension additions until `emergencyReplaceProtectedModule` | ||
* is executed. |
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.
ro resolveEmergency
is called by the methodologist
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.
contracts/manager/BaseManager.sol
Outdated
protectedModules[_module].authorizedAdapters[adapter] = false; | ||
} | ||
|
||
delete protectedModules[_module].authorizedAdaptersList; |
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.
Do we need to delete this if we're deleting protectedModules[_module]
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.
contracts/manager/BaseManager.sol
Outdated
* @param _module Module to remove | ||
*/ | ||
function removeModule(address _module) external onlyOperator { | ||
require(!protectedModules[_module].isProtected, "Module protected"); |
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.
Let's add a note that any extensions associated with the module need to be removed in a separate transaction
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.
contracts/manager/BaseManager.sol
Outdated
* @param _module Module to protect | ||
* @param _adapters Array of adapters to authorize for protected module | ||
*/ | ||
function protectModule(address _module, address[] memory _adapters) |
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.
Seems like there's an inconsistency in extension authorization between this and authorizeAdapter
. Here there's no check to see if the extension has already been added (not authorized!) whereas the authorizeAdapter
there's an explicit check to see if it has been added:
See Line 259
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.
I would tend towards not requiring the extension to have been "added" before being "authorized"
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.
As noted above - authorizeAdapter
and protectModule
now both automatically add the adapter if missing with ebd8676
contracts/manager/BaseManager.sol
Outdated
|
||
/** | ||
* MUTUAL UPGRADE**: Revokes adapter authorization for a protected module. Operator and Methodologist | ||
* must each call this function to execute the update. |
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.
Would note here that in order to remove the extension completely from the contract removeAdapter
must be called by the operator
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.
63062bd
to
feaf6a2
Compare
5c16b6a
to
cbe93be
Compare
e151766
to
cbb6b7c
Compare
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.
Couple small things but looks really good to go to me. The tests especially are amazing, super well done and thorough. Those tests help inspire confidence.
* ANYONE CALLABLE: Accrues fees from streaming fee module. Gets resulting balance after fee accrual, calculates fees for | ||
* operator and methodologist, and sends to each. NOTE: mint/redeem fees will automatically be sent to this address so reading | ||
* the balance of the SetToken in the contract after accrual is sufficient for accounting for all collected fees. | ||
* operator and methodologist, and sends to operator and methodologist, and sends to operatorFeeRecipient and methodlogist |
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.
Redundant statement here. Also methodologist
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.
|
||
event FeesAccrued(address indexed _operator, address indexed _methodologist, uint256 _operatorTake, uint256 _methodologistTake); | ||
|
||
event FeesDistributed( |
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.
Don't know if IC analytics is looking for the FeesAccrued
event but should let them know this is changed if they are. Think it's definitely better naming
/** | ||
* ONLY OPERATOR: Updates streaming fee on StreamingFeeModule. NOTE: This will accrue streaming fees though not send to operator | ||
* and methodologist. | ||
* MUTUAL UPGRADE: Updates streaming fee on StreamingFeeModule. NOTE: This will accrue streaming |
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.
Maybe we should make a note for all of these mutualUpgrade
and timeLockUpgrade
combo functions that it will require each party submitting two txns. One to set the timelock and the next to execute the function
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.
contracts/manager/BaseManager.sol
Outdated
require(isAdapter[_adapter], "Adapter does not exist"); | ||
require(!protectedModules[_module].authorizedAdapters[_adapter], "Adapter already authorized"); | ||
|
||
if (!isAdapter[_adapter]) { |
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.
Bit of a nit: But we can maybe DRY this up a bit more by making an internal function that does the state updates. That can be used here and in protectModule
.
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.
test/manager/baseManagerV2.spec.ts
Outdated
subjectProtectedModules = [subjectModule]; | ||
}); | ||
|
||
// This test is borked... module initialized in before block.. |
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.
what's wrong with this test?
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.
Whoah! Glad you flagged this. The constructor does not add modules to the SetToken. I don't this this is possible - the setToken.addModule
call reverts with Manager only
because the manager contract doesn't technically exist yet.
So ... this situation is a little weird. You could protect a module in the Manager deployment which isn't on the token.
Have removed the bad test and replaced with one where non-added module is protected in the constructor and operator adds module after deployment.
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 I think this is ok
}); | ||
}); | ||
|
||
// This test for the coverage report - hits an alternate branch condition the authorized |
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.
good to note
@@ -0,0 +1,1710 @@ | |||
import "module-alias/register"; |
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.
These tests are amazing and so thorough. Well laid out and even checking to make sure all critical pieces of state remain unchanged within different flows. This is chef's kiss.
contracts/manager/BaseManagerV2.sol
Outdated
|
||
_protectModule(_newModule, _newExtensions); | ||
|
||
ReplacedProtectedModule(_oldModule, _newModule, _newExtensions); |
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.
Do we not need the emit
here?
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.
Apparently it just works. However added the missing ones for consistency's sake in 87c8fcf
Have added some new changes to address bugs / issues discovered this morning:
The |
Updated javadocs for GeneralIndexModule.
PR implements
Summary
mutualUpgrade
in existing fee extension contractsfeeRecipient
to firewall fees from other extensions.New Permissions
The permissions model proposed here has the following properties:
TODO
Open Questions
Have retained the "adapter" naming convention to reduce noise in the diff. This PR might be the right time to rename everything
extension
?There's an asymmetry in the preconditions for replacing modules vs. protecting them.
The idea behind this is that in the "replacement" scenario, we don't really want the operator to double-up fee modules - it's cleaner to model as an atomic swap. In the "protect" scenario, the operator is adding new features and should have more flexibility. Does this make sense? Or should behavior in these two scenarios be standardized?