Skip to content
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

feat: OwnerProxy #116

Merged
merged 18 commits into from
Jun 2, 2022
Merged

feat: OwnerProxy #116

merged 18 commits into from
Jun 2, 2022

Conversation

maximebrugel
Copy link
Contributor

@maximebrugel maximebrugel commented May 16, 2022

image

In order to complete the ownership architecture, we need the OwnerProxy contract in charge of executing scripts for the Timelock (run transactions atomically).

To show how the contract works, I added two scripts :

  • AddOperator.sol, to add an operator (import, add and rebuild cache)
  • UpdateFees, to update the entry and exit fees.

We can also use a single OwnerProxy, but it must use upgradeToAndCall to call the NestedFactory owner functions :

image

@maximebrugel maximebrugel added the To review Let people know this PR is ready for a review label May 16, 2022
).to.be.revertedWith("NF: ZERO_FEES");
});

it("Cant update fees if wrong exit fees is zero", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it("Cant update fees if wrong exit fees is zero", async () => {
it("Cant update fees if exit fees are zero", async () => {

});

describe("Update fees", () => {
it("Cant update fees if wrong entry fees is zero", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it("Cant update fees if wrong entry fees is zero", async () => {
it("Cant update fees if entry fees are zero", async () => {

});
});

describe("Add operator", () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test that should revert if the calldata NestedFactory address is zero

IOperatorResolver.Operator memory operator,
bytes32 name
) external {
IOperatorResolver resolver = IOperatorResolver(MixinOperatorResolver(nestedFactory).resolver());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case the address of the NestedFactory is not correct, wouldn't it be cheaper in gas to make a require to check it first?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, but we must check the operator and factory address before

contract OwnerProxy is Ownable {
/// @notice Execute atomic actions. Only the owner can call this function (e.g. the timelock)
/// @param _target Address of the "script" to perform a delegatecall
/// @param _data The bytes calldata (bytes4 selector must be included)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(bytes4 selector must be included) should be a /// @dev imo

import "../../interfaces/IOperatorResolver.sol";
import "../../abstracts/MixinOperatorResolver.sol";

contract AddOperator {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be great to also have the RemoveOperator ready to prevent making mistakes if we ever need to do it urgently.

@adrien-supizet adrien-supizet added Fix and merge Minor changes required and removed To review Let people know this PR is ready for a review labels May 18, 2022
.execute(scriptAddOperator.address, scriptAddOperatorCalldata);
});

it("Cant remove operator if nested factory address is zero", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it("Cant remove operator if nested factory address is zero", async () => {
it("Cannot remove operator if nested factory address is zero", async () => {

or

Suggested change
it("Cant remove operator if nested factory address is zero", async () => {
it("Can't remove operator if nested factory address is zero", async () => {

IOperatorResolver resolver = IOperatorResolver(MixinOperatorResolver(nestedFactory).resolver());

// Init arrays
uint256 operatorLength = operators.length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint256 operatorLength = operators.length;
uint256 operatorLength = operators.length;
require(operatorLength != 0, "DAO-SCRIPT: INVALID_OPERATOR_LEN");

operators[i].selector
);
names[i] = operators[i].name;
operatorsToImport[i] = operator;
Copy link
Contributor

@Yashiru Yashiru May 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe store the new IOperatorResolver.Operator directly in the operatorsToImport array instead of storing it in a memory cached variable and then store it in the array, can save some gas.

Suggested change
operatorsToImport[i] = operator;
operatorsToImport[i] = IOperatorResolver.Operator(
deployedAddress,
operators[i].selector
);;

INestedFactory(nestedFactory).addOperator(operators[i].name);
}

require(MixinOperatorResolver(nestedFactory).isResolverCached(), "DAO-SCRIPT: UNRESOLVED_CACHE");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not very familiar with the MixinOperatorResolver, I wonder if this line is absolutely mandatory?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not mandatory, but good to have

bytes memory bytecode,
tupleOperator[] memory operators
) external {
require(nestedFactory != address(0), "DAO-SCRIPT: INVALID_FACTORY_ADDRESS");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change code errors to sting < 32 bytes. I know it's not important here, but it will be raised in audits later.

Comment on lines 21 to 22
bytes memory bytecode,
tupleOperator[] memory operators
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit confusing:

  • method name is singular
  • one bytecode as param

but:

  • operators param as an array - plural

Consider renaming operators

Copy link
Contributor Author

@maximebrugel maximebrugel May 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the OperatorResolver, an Operator is an address (implementation) and a bytes4 (selector), linked to a bytes32 (name).

The bytecode param will be deployed and as a result, the implementation (address).
So, the operators is the array with name and selector, it is really an "operator" list to add.

I don't know how we could rename operators. Any idea ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove tuple from the tupleOperator name, it is explicit by looking at the type, no ?
Maybe name the struct operatorFunction and the array operatorFunctions ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand how it works, then the method name is inaccurate, and should be plural.

Either the operator is the contract, or it's the address + selector + bytes. It just needs to be consistent across the protocol

Copy link
Contributor Author

@maximebrugel maximebrugel May 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adrien-supizet I misunderstood, I'm updating to DeployAddOperators

operatorsToImport[0] = IOperatorResolver.Operator({ implementation: address(0), selector: bytes4(0) });
destinations[0] = MixinOperatorResolver(nestedFactory);

IOperatorResolver(resolver).importOperators(names, operatorsToImport, destinations);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

importOperators It does not look like we're removing an operator here. Am I missing something?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm missing something here, I'll take a look at NestedFactory's removeOperator method before finishing the review

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I think the OperatorResolver should have had a removeOperators method, but this works too.

@maximebrugel maximebrugel merged commit 904f22e into master Jun 2, 2022
@maximebrugel maximebrugel deleted the owner-proxy branch June 2, 2022 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fix and merge Minor changes required
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants