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

Configurator #160

Merged
merged 26 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a63ce2e
Set up basic configurator
kevincheng96 Feb 8, 2022
8be937d
Add storage for configurator
kevincheng96 Feb 9, 2022
5c4cb42
Set up CometProxyAdmin and get deployment and scenarios working
kevincheng96 Feb 9, 2022
c38a396
Add add asset functionality
kevincheng96 Feb 10, 2022
c36d406
Create separate upgradeable configurator contract that the proxy fall…
kevincheng96 Feb 19, 2022
e920016
Add space
kevincheng96 Feb 19, 2022
3f1df57
Move upgradeTo logic from Configurator to ProxyAdmin
kevincheng96 Feb 23, 2022
867b3aa
Update _CONFIGURATOR_SLOT
kevincheng96 Feb 23, 2022
d2361a4
Implement simple configurator flow, where configurator has its own proxy
kevincheng96 Feb 24, 2022
7c39531
Introduce the ProxyAdminAdmin; add Configurator unit tests
kevincheng96 Feb 28, 2022
fdf7b30
Set up configurator migrations on Kovan and test e2e flow using a sim…
kevincheng96 Mar 2, 2022
420947c
Update TUP proxy's impl to be callable by admin instead of using a Pr…
kevincheng96 Mar 4, 2022
4a14f1d
Get scenarios working on all bases; deploy configurator to Fuji
kevincheng96 Mar 5, 2022
53b653b
Update roots.json for kovan and fuji
kevincheng96 Mar 7, 2022
b785627
Clear github actions cache
kevincheng96 Mar 7, 2022
9d91b58
Move Timelock.sol under contracts/test
kevincheng96 Mar 7, 2022
59ced11
Move configurator deployments to the bootstrapping migration scripts
kevincheng96 Mar 8, 2022
c8788d1
Get rid of setConfiguration()
kevincheng96 Mar 8, 2022
0590104
Move modified vendor contracts into contracts/vendored and update REA…
kevincheng96 Mar 8, 2022
e851199
Use a version storage slot to gate the initializer in Configurator
kevincheng96 Mar 8, 2022
d36f18e
Small code cleanup
kevincheng96 Mar 8, 2022
f6d5628
Simplify deployAndUpgradeTo() and delete unused ITransparentUpgradeab…
kevincheng96 Mar 15, 2022
381ed9d
Rebase; Move comet proxy contracts from contracts/vendored to contrac…
kevincheng96 Mar 30, 2022
571aed6
Disable solhint on one line
kevincheng96 Mar 30, 2022
ab3fb38
XXX for MAX_ASSETS check in configurator
kevincheng96 Mar 30, 2022
82b2e5e
Update roots
kevincheng96 Mar 30, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/run-scenarios.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
!deployments/**/relations.ts
!deployments/**/configuration.json
!deployments/**/migrations/*
key: deployments-v3
key: deployments-v4

- name: Install packages
run: yarn install --non-interactive --frozen-lockfile && yarn build
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ An example deployment command looks like:

`yarn deploy --network fuji`

## Vendor contracts

Third-party contracts (e.g. OZ proxies) live under `contracts/vendor`.

There are currently two Comet-related contracts that extend directly from the vendor contracts. The contracts are:

1. **TransparentUpgradeableConfiguratorProxy**: This contract extends OZ's `TransparentUpgradeableProxy`. We override the `_beforeFallback` function so that the proxy's admin can directly call the implementation. We only need this feature for the Configurator's proxy.
2. **CometProxyAdmin**: This contract extends OZ's `ProxyAdmin`. We created a new function called `deployAndUpgradeTo`, which calls `Configurator.deploy()` and upgrades Comet proxy's implementation to this newly deployed Comet contract. This function is needed so we can pass the address of the new Comet to the `Proxy.upgrade()` call in one transaction.

## Usage

Look at the scripts section inside `package.json` to find all commands.
Expand Down
2 changes: 1 addition & 1 deletion contracts/CometFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "./Comet.sol";
import "./CometConfiguration.sol";

contract CometFactory is CometConfiguration {
function clone(Configuration memory config) external returns (address) {
function clone(Configuration calldata config) external returns (address) {
return address(new Comet(config));
}
}
22 changes: 22 additions & 0 deletions contracts/CometProxyAdmin.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: XXX ADD VALID LICENSE
pragma solidity ^0.8.11;

import "./vendor/proxy/transparent/ProxyAdmin.sol";

interface Deployable {
function deploy() external returns (address);
}

contract CometProxyAdmin is ProxyAdmin {
/**
* @dev Deploy a new Comet and upgrade the implementation of the Comet proxy.
*
* Requirements:
*
* - This contract must be the admin of `CometProxy`.
*/
function deployAndUpgradeTo(Deployable configuratorProxy, TransparentUpgradeableProxy cometProxy) public virtual onlyOwner {
address newCometImpl = configuratorProxy.deploy();
upgrade(cometProxy, newCometImpl);
}
}
74 changes: 74 additions & 0 deletions contracts/Configurator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: XXX ADD VALID LICENSE
pragma solidity ^0.8.11;

import "./CometFactory.sol";
import "./CometConfiguration.sol";
import "./ConfiguratorStorage.sol";

contract Configurator is ConfiguratorStorage {

/// @notice An event emitted when a new version Comet is deployed.
event CometDeployed(address newCometAddress); // XXX Get rid of uses of the `Comet` name
event AdminTransferred(address oldAdmin, address newAdmin);

/// @notice An error given unauthorized method calls
error Unauthorized();
error AlreadyInitialized();
error InvalidAddress();

/// @notice Initializes the storage for Configurator
function initialize(address _admin, address _factory, Configuration calldata _config) public {
if (version != 0) revert AlreadyInitialized();
if (_admin == address(0)) revert InvalidAddress();
if (_factory == address(0)) revert InvalidAddress();

admin = _admin;
factory = _factory;
configuratorParams = _config;
version = 1;
}

/// @notice Sets the factory for Configurator
/// @dev only callable by admin
function setFactory(address _factory) external {
if (msg.sender != admin) revert Unauthorized();
factory = _factory;
}

// XXX Define other setters for setting params
/// @dev only callable by admin
function setGovernor(address _governor) external {
kevincheng96 marked this conversation as resolved.
Show resolved Hide resolved
if (msg.sender != admin) revert Unauthorized();
configuratorParams.governor = _governor;
}

// XXX What about removing an asset?
// XXX Should we check MAX_ASSETS here as well?
/// @dev only callable by admin
function addAsset(AssetConfig calldata asset) external {
if (msg.sender != admin) revert Unauthorized();
configuratorParams.assetConfigs.push(asset);
kevincheng96 marked this conversation as resolved.
Show resolved Hide resolved
}

/// @notice Gets the configuration params
function getConfiguration() external view returns (Configuration memory) {
return configuratorParams;
}

/// @notice Deploy a new version of the Comet implementation.
/// @dev callable by anyone
function deploy() external returns (address) {
address newComet = CometFactory(factory).clone(configuratorParams);
emit CometDeployed(newComet);
return newComet;
}

/// @notice Transfers the admin rights to a new address
/// @dev only callable by admin
function transferAdmin(address newAdmin) external {
if (msg.sender != admin) revert Unauthorized();
address oldAdmin = admin;
admin = newAdmin;
emit AdminTransferred(oldAdmin, newAdmin);
}
}
28 changes: 28 additions & 0 deletions contracts/ConfiguratorStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: XXX ADD VALID LICENSE
pragma solidity ^0.8.11;

import "./CometConfiguration.sol";

/**
* @title Compound's Comet Configuration Storage Interface
* @dev Versions can enforce append-only storage slots via inheritance.
* @author Compound
*/
contract ConfiguratorStorage is CometConfiguration {
/// @notice The current version of Configurator. This version should be
/// checked in the initializer function.
uint public version;

/// @notice Configuration settings used to deploy new Comet instances
/// by the configurator
/// @dev This needs to be internal to avoid a `CompilerError: Stack too deep
kevincheng96 marked this conversation as resolved.
Show resolved Hide resolved
/// when compiling inline assembly` error that is caused by the default
/// getters created for public variables.
Configuration internal configuratorParams; // XXX can create a public getter for this

/// @notice The admin of the protocol
address public admin;

/// @notice Address for the Comet factory contract
address public factory;
}
21 changes: 21 additions & 0 deletions contracts/TransparentUpgradeableConfiguratorProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: XXX ADD VALID LICENSE
pragma solidity ^0.8.11;

import "./vendor/proxy/transparent/TransparentUpgradeableProxy.sol";

/**
* @dev A TransparentUpgradeableProxy that allows its admin to call its implementation.
*/
contract TransparentUpgradeableConfiguratorProxy is TransparentUpgradeableProxy {
kevincheng96 marked this conversation as resolved.
Show resolved Hide resolved
/**
* @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
* optionally initialized with `_data` as explained in {UpgradeableProxy-constructor}.
*/
constructor(address _logic, address _admin, bytes memory _data) payable TransparentUpgradeableProxy(_logic, _admin, _data) {}

// XXX triple check!
/**
* @dev Overrides the TransparentUpgradeableProxy's _beforeFallback so admin can call the implementation.
*/
function _beforeFallback() internal virtual override {}
}
25 changes: 25 additions & 0 deletions contracts/test/Timelock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: XXX ADD VALID LICENSE

pragma solidity ^0.8.11;

/**
* @dev Simple Timelock for more realistic deployments and scenarios.
kevincheng96 marked this conversation as resolved.
Show resolved Hide resolved
*/
contract Timelock {

function execute(address[] calldata targets, uint[] calldata values, string[] calldata signatures, bytes[] calldata data) public {
for (uint i = 0; i < targets.length; i++) {
bytes memory callData;

if (bytes(signatures[i]).length == 0) {
callData = data[i];
} else {
callData = abi.encodePacked(bytes4(keccak256(bytes(signatures[i]))), data[i]);
}

// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = targets[i].call{value: values[i]}(callData);
require(success, "failed to call");
}
}
}
4 changes: 2 additions & 2 deletions deployments/fuji/configuration.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"symbol": "📈USDC",
"governor": "0xdd940fc821853799eaf27e9eb0a420ed3bcdc3ef",
"pauseGuardian": "0xdd940fc821853799eaf27e9eb0a420ed3bcdc3ef",
"governor": "0x1C2C3c2E3232080e0738187520372e30Ce2e34CB",
"pauseGuardian": "0x1C2C3c2E3232080e0738187520372e30Ce2e34CB",
"baseToken": "USDC",
"baseTokenPriceFeed": "0x7898AcCC83587C3C55116c5230C17a6Cd9C71bad",
"reserveRate": 0.1,
Expand Down
17 changes: 9 additions & 8 deletions deployments/fuji/migrations/1644432723_deploy_fuji.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,20 @@ migration('1644432723_deploy_fuji', {
)
);
await wait(usdc.configureMinter(signerAddress, exp(10000, 6)));
await wait(usdc.mint(signerAddress, exp(10000, 6)));

let wbtc = await deploymentManager.clone(cloneAddr.wbtc, [], cloneNetwork);
kevincheng96 marked this conversation as resolved.
Show resolved Hide resolved
// Give signer 1000 WBTC
await wait(
usdc.mint(
wbtc.mint(
signerAddress,
exp(10000, 6),
exp(10000, 8),
'0x0000000000000000000000000000000000000000',
0,
'0x0000000000000000000000000000000000000000000000000000000000000000'
)
);

let wbtc = await deploymentManager.clone(cloneAddr.wbtc, [], cloneNetwork);
// Give signer 1000 WBTC
await wait(wbtc.mint(signerAddress, exp(1000, 8)));

let wavax = await deploymentManager.clone(cloneAddr.wavax, [], cloneNetwork);
// Give admin 0.01 WAVAX tokens [this is a precious resource here!]
await wait(wavax.deposit({ value: exp(0.01, 18) }));
Expand All @@ -78,10 +78,11 @@ migration('1644432723_deploy_fuji', {
['WAVAX', wavax],
]);

let { comet, proxy } = await deployNetworkComet(deploymentManager, true, {}, contracts);
let { cometProxy, configuratorProxy } = await deployNetworkComet(deploymentManager, true, {}, contracts);

return {
comet: proxy.address,
comet: cometProxy.address,
configurator: configuratorProxy.address,
usdc: usdc.address,
wbtc: wbtc.address,
wavax: wavax.address,
Expand Down
6 changes: 5 additions & 1 deletion deployments/fuji/roots.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
{
kevincheng96 marked this conversation as resolved.
Show resolved Hide resolved
"comet": "0xd0E4a32790B5875Df3b8360286dea88382662069"
"comet": "0x5Da5c1aDe062dbEad369a70876D12e554eF610a1",
"configurator": "0x4efA5fb9682F373823F025fCaC4e5CFD2a405B10",
"usdc": "0x56C25B0D28382764460636a642e985a674E03e89",
"wbtc": "0xc0C282615f322B2FBefe6f974CFc2e28d9b4bb86",
"wavax": "0xDFCF797509905E71B6258444Bf1657B300D7Ae8B"
}
4 changes: 2 additions & 2 deletions deployments/kovan/configuration.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
kevincheng96 marked this conversation as resolved.
Show resolved Hide resolved
"symbol": "📈USDC",
"governor": "0xdd940fc821853799eaf27e9eb0a420ed3bcdc3ef",
"pauseGuardian": "0xdd940fc821853799eaf27e9eb0a420ed3bcdc3ef",
"governor": "0x1C2C3c2E3232080e0738187520372e30Ce2e34CB",
"pauseGuardian": "0x1C2C3c2E3232080e0738187520372e30Ce2e34CB",
"baseToken": "USDC",
"baseTokenPriceFeed": "0x9211c6b3BF41A10F78539810Cf5c64e1BB78Ec60",
"reserveRate": 0.1,
Expand Down
5 changes: 3 additions & 2 deletions deployments/kovan/migrations/1644388553_deploy_kovan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,11 @@ migration('1644388553_deploy_kovan', {
['LINK', link],
]);

let { comet, proxy } = await deployNetworkComet(deploymentManager, true, {}, contracts);
let { cometProxy, configuratorProxy } = await deployNetworkComet(deploymentManager, true, {}, contracts);

return {
comet: proxy.address,
comet: cometProxy.address,
configurator: configuratorProxy.address,
usdc: usdc.address,
wbtc: wbtc.address,
weth: weth.address,
Expand Down
15 changes: 8 additions & 7 deletions deployments/kovan/roots.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"comet": "0x93C747aa42548C12C58Da2cbC10C171342E2b3c2",
"usdc": "0xA2202bF3D1230E3F0cE46c7890e8b83A5110Ca2f",
"wbtc": "0xE16D6Bf3661403913A13D97D713803CcE4737B8B",
"weth": "0x2D3ee41eF0DcaFCa72C5C24D61437a09ca7cf460",
"comp": "0x1193A0C63d82701d4267980B4Ae7323955337Cc0",
"uni": "0xE1939AE051cc719E8bf20573CdB076319728B2c6",
"link": "0x3509DAfFBE157183af358f42a8Cd245A522A0398"
"comet": "0xb86D3bc4661DE67Fc92071b1FAE802C9b6Ae89F4",
"configurator": "0xcB6C34E704cb5c048e9D7B33E95aD0a5c993b78E",
"usdc": "0x38F2c0081f6Df09bC6c5040e711D6bf7AdC912aa",
"wbtc": "0xC821255246e454d66e0aD5De3A9eD7122AcFA48F",
"weth": "0xd766d103C14006cEa982AA45030B1eB984B693fc",
"comp": "0x773A57aA7C6dEd6C9d3B74079B79a16745748101",
"uni": "0xc2DC732Bb078cD48AB9791ebC4f68F4796b4C743",
"link": "0x6e9834EEbdF9bB62085Af3D035A6d7b03bB5eBf3"
}
23 changes: 23 additions & 0 deletions deployments/relations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,29 @@ let relationConfigMap: RelationConfigMap = {
},
relations: {},
},
configurator: {
proxy: {
field: {
slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc',
}
},
relations: {
configuratorAdmin: {
field: {
slot: '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103',
}
}
}
},
cometAdmin: {
relations: {
timelock: {
field: async (cometAdmin) => {
return await cometAdmin.owner();
}
}
}
},
FiatTokenProxy: {
proxy: {
field: {
Expand Down
Loading