Skip to content

Commit

Permalink
Merge pull request #265 from Fujicracy/protocol/docs/review-code-comm…
Browse files Browse the repository at this point in the history
…ents

Improve code comments in Chief and Routers
  • Loading branch information
0xdcota authored Feb 1, 2023
2 parents 504c147 + 9ba438d commit 1b939ec
Show file tree
Hide file tree
Showing 121 changed files with 4,781 additions and 3,059 deletions.
230 changes: 189 additions & 41 deletions packages/protocol/src/Chief.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
pragma solidity 0.8.15;

/**
* @title Chief.
* @author fujidao Labs
* @notice Controls vault deploy factories, deployed flashers, vault ratings and core access control.
* Vault deployer contract with template factory allow.
* ref: https://github.com/sushiswap/trident/blob/master/contracts/deployer/MasterDeployer.sol
* @title Chief
*
* @author Fujidao Labs
*
* @notice Controls vault deploy factories, deployed flashers, vault ratings and core access control.
*
* @dev Deployments of new vaults are done through this contract that also stores the addresses of all
* deployed vaults.
*/

import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol";
Expand All @@ -22,12 +25,60 @@ import {CoreRoles} from "./access/CoreRoles.sol";
contract Chief is CoreRoles, AccessControl, IChief {
using Address for address;

event OpenVaultFactory(bool state);
/**
* @dev Emitted when the deployements of new vaults is alllowed/disallowed.
*
* @param allowed "true" to allow, "false" to disallow
*/
event AllowPermissionlessDeployments(bool allowed);

/**
* @dev Emitted when a new vault gets deployed.
*
* @param factory address of the factory through which to deploy
* @param vault address of the newly deployed vault
* @param deployData encoded args used to deploy the vault
*/
event DeployVault(address indexed factory, address indexed vault, bytes deployData);

/**
* @dev Emitted when `_vaults` are set through `setVaults()`.
*
* @param previousVaults addresses
* @param newVaults addresses
*/
event SetVaults(address[] previousVaults, address[] newVaults);

/**
* @dev Emitted when a new flasher is alllowed/disallowed.
*
* @param flasher address of the flasher
* @param allowed "true" to allow, "false" to disallow
*/
event AllowFlasher(address indexed flasher, bool allowed);

/**
* @dev Emitted when a new factory is alllowed/disallowed.
*
* @param factory address of the factory
* @param allowed "true" to allow, "false" to disallow
*/
event AllowVaultFactory(address indexed factory, bool allowed);
event TimelockUpdated(address indexed timelock);
event SafetyRatingChange(address vault, uint256 newRating);

/**
* @dev Emitted when a new `timelock` is set.
*
* @param timelock address of the new timelock
*/
event UpdateTimelock(address indexed timelock);

/**
* @dev Emitted when a new rating is attributed to a vault.
*
* @param vault address of the vault
* @param newRating value of the new rating
*/
event ChangeSafetyRating(address indexed vault, uint256 newRating);

/// @dev Custom Errors
error Chief__checkInput_zeroAddress();
Expand All @@ -39,13 +90,20 @@ contract Chief is CoreRoles, AccessControl, IChief {
error Chief__checkRatingValue_notInRange();
error Chief__checkValidVault_notValidVault();

/**
* @dev When `permissionlessDeployments` is "false", only addresses with this role
* can deploy new vaults.
*/
bytes32 public constant DEPLOYER_ROLE = keccak256("DEPLOYER_ROLE");

address public timelock;
address public addrMapper;
bool public openVaultFactory;

/// @dev Control who can deploy new vaults through `deployVault()`
bool public permissionlessDeployments;

address[] internal _vaults;

mapping(address => uint256) public vaultSafetyRating;
mapping(address => bool) public allowedVaultFactory;
mapping(address => bool) public allowedFlasher;
Expand All @@ -66,10 +124,26 @@ contract Chief is CoreRoles, AccessControl, IChief {
if (deployAddrMapper) _deployAddrMapper();
}

/**
* @notice Gets an array with all deployed vaults.
*/
function getVaults() external view returns (address[] memory) {
return _vaults;
}

/**
* @notice Sets a new timelock.
*
* @param newTimelock address of the new timelock contract
*
* @dev Requirements:
* - Must be restricted to timelock.
* - Revokes `DEFAULT_ADMIN_ROLE` from the existing timelock.
* - Grants `DEFAULT_ADMIN_ROLE` to `newTimelock`.
* - `newTimelock` must be a non-zero address.
* - Emits a `UpdateTimelock` event.
*
*/
function setTimelock(address newTimelock) external onlyTimelock {
_checkInputIsNotZeroAddress(newTimelock);
// Revoke admin role from current timelock
Expand All @@ -78,14 +152,56 @@ contract Chief is CoreRoles, AccessControl, IChief {
timelock = newTimelock;
// grant admin role to new timelock address
_grantRole(DEFAULT_ADMIN_ROLE, timelock);
emit TimelockUpdated(newTimelock);
emit UpdateTimelock(newTimelock);
}

function setOpenVaultFactory(bool state) external onlyTimelock {
openVaultFactory = state;
emit OpenVaultFactory(state);
/**
* @notice Clears and sets the `vaults` recorded in this {Chief-_vaults}.
*
* @param vaults addresses that should be recorded
*
* @dev This method should only be used in extraordinary cases.
* Requirements:
* - Must be called from a timelock.
*/
function setVaults(address[] memory vaults) external onlyTimelock {
address[] memory previous = _vaults;
delete _vaults;
_vaults = vaults;
emit SetVaults(previous, _vaults);
}

/**
* @notice Sets `permissionlessDeployments`.
*
* @param allowed anyone can deploy a vault when "true",
* otherwise only address with a DEPLOYER_ROLE
*
* @dev Requirements:
* - Must be restricted to timelock.
* - Emits a `AllowPermissionlessDeployments` event.
*/
function setPermissionlessDeployments(bool allowed) external onlyTimelock {
permissionlessDeployments = allowed;

emit AllowPermissionlessDeployments(allowed);
}

/**
* @notice Deploys a new vault through a factory, attribute an intial rating and
* store new vault's address in `_vaults`.
*
* @param factory allowed vault factory contract
* @param deployData encoded data that will be used in the factory to create a new vault
* @param rating initial rating attributed to the new vault
*
* @dev Requirements:
* - Must use an allowed factory.
* - Msg.sender must have `DEPLOYER_ROLE` if `permissionlessDeployments` is "false".
* - `rating` must be in range (1,100].
* - Emits a `DeployVault` event.
*
*/
function deployVault(
address factory,
bytes calldata deployData,
Expand All @@ -97,7 +213,7 @@ contract Chief is CoreRoles, AccessControl, IChief {
if (!allowedVaultFactory[factory]) {
revert Chief__deployVault_factoryNotAllowed();
}
if (!openVaultFactory && !hasRole(DEPLOYER_ROLE, msg.sender)) {
if (!permissionlessDeployments && !hasRole(DEPLOYER_ROLE, msg.sender)) {
revert Chief__deployVault_missingRole(msg.sender, DEPLOYER_ROLE);
}
_checkRatingValue(rating);
Expand All @@ -111,37 +227,55 @@ contract Chief is CoreRoles, AccessControl, IChief {

/**
* @notice Sets `vaultSafetyRating` for `vault`.
* Requirements:
* - Emits a `SafetyRatingChange` event.
*
* @param vault address of the vault whose rating will be changed
* @param newRating a new value for the rating
*
* @dev Requirements:
* - Emits a `ChangeSafetyRating` event.
* - Only timelock can change rating.
* - `newRating` is in range [1=100].
* - `vault_` is not zero address.
* - `newRating` is in range (1,100].
* - `vault` is a non-zero address and is contained in `_vaults`.
*/
function setSafetyRating(address vault, uint256 newRating) external onlyTimelock {
_checkValidVault(vault);
_checkRatingValue(newRating);

vaultSafetyRating[vault] = newRating;

emit SafetyRatingChange(vault, newRating);
emit ChangeSafetyRating(vault, newRating);
}

/**
* @notice Set `flasher` as an authorized address for flashloan operations.
* - Emits a `AllowFlasher` event.
* @notice Sets `flasher` as an authorized address for flashloan operations.
*
* @param flasher Address of the flasher to allow/disallow.
* @param allowed "true" to allow, "false" to disallow.
*
* @dev Requirements:
* - `flasher` must be a non-zero address.
* - `allowed` must be different the previously recorded for the same `flasher`.
* - Emits a `AllowFlasher` event.
*/
function allowFlasher(address flasher, bool allowed) external onlyTimelock {
_checkInputIsNotZeroAddress(flasher);
if (allowedFlasher[flasher] == allowed) {
revert Chief__allowFlasher_noAllowChange();
}
allowedFlasher[flasher] = allowed;

emit AllowFlasher(flasher, allowed);
}

/**
* @notice Sets `factory` as an authorized address for vault deployments.
* - Emits a `AllowVaultFactory` event.
*
* @param factory address of the factory to allow/disallow
* @param allowed "true" to allow, "false" to disallow
*
* @dev Requirements:
* - `allowed` must be different than previously recorded.
* - Emits a `AllowVaultFactory` event.
*/
function allowVaultFactory(address factory, bool allowed) external onlyTimelock {
_checkInputIsNotZeroAddress(factory);
Expand All @@ -153,9 +287,10 @@ contract Chief is CoreRoles, AccessControl, IChief {
}

/**
* @notice Force pauses all actions from all vaults in `_vaults`.
* Requirement:
* - Should be restricted to pauser role.
* @notice Force pause all actions from all vaults in `_vaults`.
*
* @dev Requirements:
* - Must be restricted to `PAUSER_ROLE`.
*/
function pauseForceAllVaults() external onlyRole(PAUSER_ROLE) {
bytes memory callData = abi.encodeWithSelector(IPausableVault.pauseForceAll.selector);
Expand All @@ -164,8 +299,9 @@ contract Chief is CoreRoles, AccessControl, IChief {

/**
* @notice Resumes all actions by force unpausing all vaults in `_vaults`.
* Requirement:
* - Should be restricted to unpauser role.
*
* @dev Requirements:
* - Must be restricted to `UNPAUSER_ROLE`.
*/
function unpauseForceAllVaults() external onlyRole(UNPAUSER_ROLE) {
bytes memory callData = abi.encodeWithSelector(IPausableVault.unpauseForceAll.selector);
Expand All @@ -174,10 +310,12 @@ contract Chief is CoreRoles, AccessControl, IChief {

/**
* @notice Pauses specific action in all vaults in `_vaults`.
* @param action Enum: 0-deposit, 1-withdraw, 2-borrow, 3-payback.
* Requirements:
* - `action` in all vaults' should be not paused; otherwise revert.
* - Should be restricted to pauser role.
*
* @param action enum: 0-deposit, 1-withdraw, 2-borrow, 3-payback.
*
* @dev Requirements:
* - `action` in all vaults' must be not paused; otherwise revert.
* - Must be restricted to `PAUSER_ROLE`.
*/
function pauseActionInAllVaults(IPausableVault.VaultActions action)
external
Expand All @@ -189,10 +327,12 @@ contract Chief is CoreRoles, AccessControl, IChief {

/**
* @notice Resumes specific `action` by unpausing in all vaults in `_vaults`.
* @param action Enum: 0-deposit, 1-withdraw, 2-borrow, 3-payback.
* Requirements:
* - `action` in all vaults' should be in paused state; otherwise revert.
* - Should be restricted to pauser role.
*
* @param action enum: 0-deposit, 1-withdraw, 2-borrow, 3-payback.
*
* @dev Requirements:
* - `action` in all vaults' must be in paused state; otherwise revert.
* - Must be restricted to `PAUSER_ROLE`.
*/
function upauseActionInAllVaults(IPausableVault.VaultActions action)
external
Expand All @@ -203,7 +343,7 @@ contract Chief is CoreRoles, AccessControl, IChief {
}

/**
* @dev Deploys 1 {TimelockController} contract during Chief deployment.
* @dev Deploys {TimelockController} contract during Chief deployment.
*/
function _deployTimelockController() internal {
address[] memory admins = new address[](1);
Expand All @@ -213,14 +353,16 @@ contract Chief is CoreRoles, AccessControl, IChief {
}

/**
* @dev Deploys 1 {AddrMapper} contract during Chief deployment.
* @dev Deploys {AddrMapper} contract during Chief deployment.
*/
function _deployAddrMapper() internal {
addrMapper = address(new AddrMapper{salt: "0x00"}(address(this)));
}

/**
* @dev executes pause state changes.
* @dev Executes pause state changes.
*
* @param callData encoded data containing pause or unpause commands.
*/
function _changePauseState(bytes memory callData) internal {
uint256 alength = _vaults.length;
Expand All @@ -233,7 +375,9 @@ contract Chief is CoreRoles, AccessControl, IChief {
}

/**
* @dev reverts if `input` is zero address.
* @dev Reverts if `input` is zero address.
*
* @param input address to verify
*/
function _checkInputIsNotZeroAddress(address input) internal pure {
if (input == address(0)) {
Expand All @@ -242,7 +386,9 @@ contract Chief is CoreRoles, AccessControl, IChief {
}

/**
* @dev reverts if `rating` input is not in range [1,100].
* @dev Reverts if `rating` input is not in range (1,100].
*
* @param rating value to verify is in the accepted range
*/
function _checkRatingValue(uint256 rating) internal pure {
if (rating == 0 || rating > 100) {
Expand All @@ -251,7 +397,9 @@ contract Chief is CoreRoles, AccessControl, IChief {
}

/**
* @dev reverts if `vault` is not in `_vaults` array.
* @dev Reverts if `vault` is an zero address and is not in `_vaults` array.
*
* @param vault address of vault to check
*/
function _checkValidVault(address vault) internal view {
_checkInputIsNotZeroAddress(vault);
Expand Down
Loading

0 comments on commit 1b939ec

Please sign in to comment.