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

VAL-114 First cut of adding an upgradeable contract #127

Merged
merged 8 commits into from
Dec 6, 2022
Merged

VAL-114 First cut of adding an upgradeable contract #127

merged 8 commits into from
Dec 6, 2022

Conversation

ams9198
Copy link
Contributor

@ams9198 ams9198 commented Dec 3, 2022

Introduces 2 patterns for upgrades:

  1. For standalone contracts, uses the UUPS pattern. Introduces an abstract DeployerUUPSUpgradeable that can be derived from to simplify usage. Basically just needs the service config to be injected into the contract, and the constructor to be implemented as an initialize method.
  2. For generated contracts, like Loan, Pool, etc. uses a Beacon proxy pattern.

For 1), I updated ServiceConfiguration to use this. For 2), I updated the PoolFactory / Pool.

/**
* @dev Whether the protocol is paused.
*/
bool public paused = false;
bool public paused;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

All non-constant values should be set in the initializer, ideally, otherwise they risk getting reset on an upgrade unexpectedly.

/**
* @inheritdoc UUPSUpgradeable
*/
function _authorizeUpgrade(address) internal override onlyDeployer {}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is where I understand the access control is enforced. I wrote tests verifying this, but it'd be great to get a 2nd set of eyes that there's not another entrypoint that I missed.

* upgrades.
*/
abstract contract DeployerUUPSUpgradeable is
IServiceConfigurable,
Copy link
Contributor Author

@ams9198 ams9198 Dec 4, 2022

Choose a reason for hiding this comment

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

Not 100% on this pattern, but the idea was:

  • Have a parent type that would force derived types to have a reference to the serviceConfig (done through IServiceConfigurable).
  • Have an abstract or concrete type that implements the critical-path, access control for upgrades (DeployerUUPSUpgradeable).

Types needing upgradeability inherit from this type, add an initialize(), ensure they have a reference to the ServiceConfig, and should be good to go.

"PerimeterPoolToken",
"PPT"
// Create beacon proxy
BeaconProxy proxy = new BeaconProxy(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the key bit

import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Annoyingly, everything needs to be the *Upgradeable OpenZep library

@@ -1421,4 +1429,25 @@ describe("Pool", () => {
);
});
});

describe("Updates", () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updates for the Pool ala beacon proxies

@@ -189,4 +205,37 @@ describe("ServiceConfiguration", () => {
);
});
});

describe("Upgrades", () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Upgrades for ServiceConfig using UUPS

/**
* Get commonly-used signers.
*/
export async function getCommonSigners() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this makes testing a lot easier, but lmk if you see any downsides...

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe bob and alice can just be bob and alice, but I think this is nice to get named accounts. Only downside is it still requires proper setup to make their semantic names accurate.

@@ -60,10 +62,7 @@ export async function deployPool({
);

const PoolFactory = await ethers.getContractFactory("PoolFactory", {
signer: poolAdmin,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

PoolFactory now longer needs it since it just emits proxies (basically blank contracts)

Copy link
Contributor

@bricestacey bricestacey left a comment

Choose a reason for hiding this comment

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

overall this looks right.

*/
modifier onlyDeployer() {
require(
msg.sender != address(0) &&
Copy link
Contributor

Choose a reason for hiding this comment

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

is msg.sender ever the null address?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so, but wasn't sure if there was some odd lifecycle consideration. Will remove if you think it's safe to do so!

@ams9198 ams9198 marked this pull request as ready for review December 6, 2022 16:51
@ams9198 ams9198 merged commit e6fe675 into circlefin:master Dec 6, 2022
@ams9198 ams9198 deleted the VAL-114 branch December 6, 2022 22:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants