-
Notifications
You must be signed in to change notification settings - Fork 27
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
[Proposed] ACP-99: Implement using composition - ValidatorManager as single entry point #668
base: main
Are you sure you want to change the base?
Conversation
I'm curious to know how much this affects gas costs, that would be one of the major advantages of keeping everything in a single contract, right? |
abstract contract ACP99ValidatorManager is IACP99ValidatorManager, ValidatorManager { | ||
IACP99SecurityModule public securityModule; | ||
|
||
// TODO: calling this should be restricted to...who? |
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.
😜
// TODO: calling this should be restricted to...who? | |
// TODO: calling this should be restricted to...whom? |
We won't know until we get unit tests working, but in theory the only added cost should be the external call to the security module. If we're not transferring ETH, and assuming the address is "warm" (it should be - every interaction will call the same security module), then gas is on the order of hundreds https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-1-call |
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 the key difference here, that the security module is a property of the validator-manager instead of the validator-manager implementing the security module interface?
// TODO: calling this should be restricted to...who? | ||
function setSecurityModule(IACP99SecurityModule _securityModule) external { | ||
securityModule = _securityModule; | ||
} |
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.
Should the security module itself control its own upgrades? If not, should there be a SecurityUpdateModule
?
bytes calldata args | ||
) external returns (bytes32){ | ||
bytes32 validationID = _initializeValidatorRegistration(input, weight); | ||
securityModule.handleInitializeValidatorRegistration(validationID, weight, args); |
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 definitely need to go through the ACP again, but I would expect the security module to do some form of validation on the inputs before calling the _initializeValidatorRegistration
. Or does it not matter since the security module will just revert anyway?
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.
It's a little tricky to reverse the order in our current implementation since the security module needs the validationID, which is provided by the manager contract. It will revert if the security module's checks fail, regardless of the ordering. We should definitely keep in mind patterns such as checks-effects-interactions if/when we decide to move forward on this implementation.
Why this should be merged
Experimental implementation of ACP-99 using composition. Concrete contracts implement either
IACP99SecurityModule
orIACP99ValidatorManager
.Notably, the contract sizes decrease significantly.
ERC20TokenStakingManager
goes from right at the 24kB size limit down to 14.6kB.This is not functional as-is, and is meant to demonstrate the necessary refactoring to implement ACP-99 using composition
How this works
This implementation deviates slightly from the ACP-99 spec as written in that the ValidatorManager is the only contract that the end user interacts with. To achieve this, the
handle*
method signatures must be generic enough to cover all possible SecurityModule use cases, notably PoA vs PoS. This results in a greater-than-minimal IACP99SecurityModule interface, where some implementations won't use certain arguments (for example PoA applications won't needpayable
methods, but native token staking applications will).How this was tested
How is this documented