Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
558dc98
fix flaky test
xklob Apr 2, 2022
4d5284d
Merge pull request #639 from fei-protocol/hotfix/hasAnyOfRolesTest
Apr 2, 2022
33b72d5
feat: revoke GOVERNOR role from Rari timelock
thomas-waite Apr 3, 2022
3f64565
refactor: add proposal config
thomas-waite Apr 3, 2022
63d0f65
refactor: validate has role to start with
thomas-waite Apr 3, 2022
24b9c02
Merge pull request #641 from fei-protocol/feat-remove-governor
thomas-waite Apr 5, 2022
d0cc9d9
feat: summary of todos
thomas-waite Apr 8, 2022
5a3d84d
refactor: replace OptimisticTimelock with TimelockController
thomas-waite Apr 9, 2022
bf0bdb4
refactor: remove transfer pod admin
thomas-waite Apr 9, 2022
866e5dc
refactor: decouple admin and factory, so can pass to factory
thomas-waite Apr 9, 2022
adb0abc
test: make tests pass
thomas-waite Apr 10, 2022
8564d15
feat: allow pods with no timelock
thomas-waite Apr 10, 2022
1c3b3d8
refactor: consolidate pod specific roles
thomas-waite Apr 10, 2022
d83dbbc
refactor: update global role allocation
thomas-waite Apr 10, 2022
a80eeb3
test: update e2e tests
thomas-waite Apr 10, 2022
bdadffe
refactor: remove unneeded latest podId, transfer orca tokens for deploy
thomas-waite Apr 10, 2022
ba3e7e9
refactor: revoke timelock admin role from factory
thomas-waite Apr 10, 2022
36808d8
refactor: make POD_ADMIN role admin the ROLE_ADMIN
thomas-waite Apr 10, 2022
65befd7
fix: PR feedback around naming
thomas-waite Apr 11, 2022
c2ec23a
refactor: move ACL extension to CoreRef
thomas-waite Apr 11, 2022
4109ff6
refactor: inject factory into podAdmin gateway
thomas-waite Apr 11, 2022
0170f9f
fix: final PR feedback
thomas-waite Apr 11, 2022
c179487
style: add delimiter to pod roles
thomas-waite Apr 12, 2022
393bf4c
Merge branch 'develop' into gov-todos
thomas-waite Apr 14, 2022
992ae29
test: update tests
thomas-waite Apr 20, 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
11 changes: 11 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
1. Do not use optimistic timelock - use the raw OZ timelock
2. Combine/aggregate some of the pod specific roles
3. Allow Orca pods to be created without a timelock
4. If min delay is defined on an orca pod, enforce a limit
5. Remove podAdminGateway migration concept from admin. Admin will be fixed (the migrated admin will lose timelock proposer/cancel access)
6. Prefix all internal methods with `_`
7. Remove burner function for pod creation. Just create inside constructor
8. Find way to stop DAO proposal being bricked by podId changing underfoot
9. DAO vote to migrate all roles

No orca controller upgrade functionality
5 changes: 0 additions & 5 deletions contracts/core/TribeRoles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,6 @@ library TribeRoles {
/*///////////////////////////////////////////////////////////////
Minor Roles
//////////////////////////////////////////////////////////////*/

/// @notice capable of deploying optimistic governance pods
bytes32 internal constant POD_DEPLOYER_ROLE =
keccak256("POD_DEPLOYER_ROLE");

bytes32 internal constant POD_METADATA_REGISTER_ROLE =
keccak256("POD_METADATA_REGISTER_ROLE");

Expand Down
1 change: 0 additions & 1 deletion contracts/dao/timelock/OptimisticTimelock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ contract OptimisticTimelock is TimelockController, CoreRef {

In addition it allows for much more granular and flexible access for multisig operators
*/
// Guardian can become admin on every Optimistic timelock and effetively become
function becomeAdmin() public onlyGuardianOrGovernor {
this.grantRole(TIMELOCK_ADMIN_ROLE, msg.sender);
}
Expand Down
182 changes: 50 additions & 132 deletions contracts/pods/PodAdminGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,132 +18,54 @@ import {IPodFactory} from "./interfaces/IPodFactory.sol";
/// 2. Removing a member from a pod
/// 3. Transferring a pod member
/// 4. Toggling a pod membership transfer switch
/// 5. Vetoing a pod proposal
contract PodAdminGateway is CoreRef, IPodAdminGateway {
/// @notice Pod factory which creates optimistic pods and acts as a source of information
IPodFactory private immutable podFactory;

constructor(address _core, address _podFactory) CoreRef(_core) {
MemberToken public immutable memberToken;

/// @notice Pod controller for the pods
ControllerV1 public immutable podController;

/// @notice Pod factory
IPodFactory public immutable podFactory;

constructor(
address _core,
address _memberToken,
address _podController,
address _podFactory
) CoreRef(_core) {
memberToken = MemberToken(_memberToken);
podController = ControllerV1(_podController);
podFactory = IPodFactory(_podFactory);
}

//////////////////////// GETTERS ////////////////////////////////
// TODO: Whatever global set of roles are, map them one to one to the specific pod roles.
// Pod specific roles:
// ADMIN: If can add, should be able to remove and lock transfers. Should also be able to veto
// GUARDIAN: Can remove and veto
//

/// @notice Calculate the specific pod admin role related to adding pod members
function getPodAddMemberRole(uint256 _podId)
/// @notice Calculate the specific pod admin role identifier
/// @dev This role is able to add pod members, remove pod members, lock and unlock transfers and veto
/// proposals
function getSpecificPodAdminRole(uint256 _podId)
public
pure
override
returns (bytes32)
{
return keccak256(abi.encode(_podId, "ORCA_POD", "POD_ADD_MEMBER_ROLE"));
return keccak256(abi.encode(_podId, "_ORCA_POD", "_ADMIN"));
}

/// @notice Calculate the pod admin role related to removing pod members
function getPodRemoveMemberRole(uint256 _podId)
/// @notice Calculate the specific pod guardian role identifier
/// @dev This role is able to remove pod members and veto pod proposals
function getSpecificPodGuardianRole(uint256 _podId)
public
pure
override
returns (bytes32)
{
return
keccak256(abi.encode(_podId, "ORCA_POD", "POD_REMOVE_MEMBER_ROLE"));
}

/// @notice Calculate the specific pod veto role, which allows an
function getPodVetoRole(uint256 _podId)
public
pure
override
returns (bytes32)
{
return keccak256(abi.encode(_podId, "ORCA_POD", "POD_VETO_ROLE"));
}

/// @notice Calculate the specific pod transfer admin role
// TODO: Remove this - not needed
function getPodTransferAdminRole(uint256 _podId)
public
pure
override
returns (bytes32)
{
return
keccak256(
abi.encode(_podId, "ORCA_POD", "POD_TRANSFER_ADMIN_ROLE")
);
}

/// @notice Calculate the specific pod membership transfer lock role
function getSetMembershipTransferLockRole(uint256 _podId)
public
pure
override
returns (bytes32)
{
return
keccak256(
abi.encode(
_podId,
"ORCA_POD",
"SET_MEMBERSHIP_TRANSFER_LOCK_ROLE"
)
);
return keccak256(abi.encode(_podId, "_ORCA_POD", "_GUARDIAN"));
}

///////////////////////// ADMIN PRIVILEDGES ////////////////////////////

/// @notice Transfer the pod admin address for a pod to another address
function transferPodAdmin(uint256 _podId, address newPodAdmin)
external
override
hasAnyOfThreeRoles(
TribeRoles.GOVERNOR,
TribeRoles.POD_ADMIN,
getPodTransferAdminRole(_podId)
)
{
_transferPodAdmin(_podId, newPodAdmin);
}

/// @notice Batch transfer the pod admin address for several pods
/// @dev Mass transfer of podAdmins only expected to be performed by GOVERNOR or POD_ADMIN
function batchTransferPodAdmins(
uint256[] calldata _podIds,
address[] calldata newPodAdmins
)
external
override
hasAnyOfTwoRoles(TribeRoles.GOVERNOR, TribeRoles.POD_ADMIN)
{
require(
_podIds.length == newPodAdmins.length,
"MISMATCHED_ARG_LENGTHS"
);
uint256 numPodsToTransfer = _podIds.length;
for (uint256 i = 0; i < numPodsToTransfer; ) {
_transferPodAdmin(_podIds[i], newPodAdmins[i]);

// i is bounded by numPodsToTransfer
unchecked {
i += 1;
}
}
}

/// @notice Transfer a pod admin from this gateway to another address
function _transferPodAdmin(uint256 _podId, address newPodAdmin) internal {
ControllerV1 podController = podFactory.podController();

address oldPodAdmin = address(this);
emit UpdatePodAdmin(_podId, oldPodAdmin, newPodAdmin);
podController.updatePodAdmin(_podId, newPodAdmin);
}

/// @notice Admin functionality to add a member to a pod
/// @dev Permissioned to GOVERNOR, POD_ADMIN and POD_ADD_MEMBER_ROLE
function addPodMember(uint256 _podId, address _member)
Expand All @@ -152,10 +74,9 @@ contract PodAdminGateway is CoreRef, IPodAdminGateway {
hasAnyOfThreeRoles(
TribeRoles.GOVERNOR,
TribeRoles.POD_ADMIN,
getPodAddMemberRole(_podId)
getSpecificPodAdminRole(_podId)
)
{
MemberToken memberToken = podFactory.getMemberToken();
_addMemberToPod(_podId, _member, memberToken);
}

Expand All @@ -177,11 +98,10 @@ contract PodAdminGateway is CoreRef, IPodAdminGateway {
hasAnyOfThreeRoles(
TribeRoles.GOVERNOR,
TribeRoles.POD_ADMIN,
getPodAddMemberRole(_podId)
getSpecificPodAdminRole(_podId)
)
{
uint256 numMembers = _members.length;
MemberToken memberToken = podFactory.getMemberToken();
for (uint256 i = 0; i < numMembers; ) {
_addMemberToPod(_podId, _members[i], memberToken);
// i is constrained by being < _members.length
Expand All @@ -196,14 +116,14 @@ contract PodAdminGateway is CoreRef, IPodAdminGateway {
function removePodMember(uint256 _podId, address _member)
external
override
hasAnyOfFourRoles(
hasAnyOfFiveRoles(
TribeRoles.GOVERNOR,
TribeRoles.POD_ADMIN,
TribeRoles.GUARDIAN,
getPodRemoveMemberRole(_podId)
getSpecificPodGuardianRole(_podId),
getSpecificPodAdminRole(_podId)
)
{
MemberToken memberToken = podFactory.getMemberToken();
_removePodMember(_podId, _member, memberToken);
}

Expand All @@ -222,15 +142,15 @@ contract PodAdminGateway is CoreRef, IPodAdminGateway {
function batchRemovePodMember(uint256 _podId, address[] calldata _members)
external
override
hasAnyOfFourRoles(
hasAnyOfFiveRoles(
TribeRoles.GOVERNOR,
TribeRoles.POD_ADMIN,
TribeRoles.GUARDIAN,
getPodRemoveMemberRole(_podId)
getSpecificPodGuardianRole(_podId),
getSpecificPodAdminRole(_podId)
)
{
uint256 numMembers = _members.length;
MemberToken memberToken = podFactory.getMemberToken();
for (uint256 i = 0; i < numMembers; ) {
_removePodMember(_podId, _members[i], memberToken);

Expand All @@ -242,60 +162,58 @@ contract PodAdminGateway is CoreRef, IPodAdminGateway {
}

/// @notice Admin functionality to turn off pod membership transfer
/// @dev Permissioned to GOVERNOR, POD_ADMIN, GUARDIAN and the specific role
/// @dev Permissioned to GOVERNOR, POD_ADMIN and the specific pod admin role
function lockMembershipTransfers(uint256 _podId)
external
override
hasAnyOfFourRoles(
hasAnyOfThreeRoles(
TribeRoles.GOVERNOR,
TribeRoles.POD_ADMIN,
TribeRoles.GUARDIAN,
getSetMembershipTransferLockRole(_podId)
getSpecificPodAdminRole(_podId)
)
{
_setMembershipTransferLock(_podId, true);
}

/// @notice Admin functionality to turn on pod membership transfers
/// @dev Permissioned to GOVERNOR, POD_ADMIN, GUARDIAN and the specific role
/// @dev Permissioned to GOVERNOR, POD_ADMIN and the specific pod admin role
function unlockMembershipTransfers(uint256 _podId)
external
override
hasAnyOfFourRoles(
hasAnyOfThreeRoles(
TribeRoles.GOVERNOR,
TribeRoles.POD_ADMIN,
TribeRoles.GUARDIAN,
getSetMembershipTransferLockRole(_podId)
getSpecificPodAdminRole(_podId)
)
{
_setMembershipTransferLock(_podId, false);
}

/// @notice Internal method to toggle a pod membership transfer lock
function _setMembershipTransferLock(uint256 _podId, bool _lock) internal {
ControllerV1 podController = podFactory.podController();
podController.setPodTransferLock(_podId, _lock);
emit PodMembershipTransferLock(_podId, _lock);
}

/////////////// VETO CONTROLLER /////////////////

/// @notice Allow a proposal to be vetoed in a pod timelock
/// @dev Permissioned to GOVERNOR, POD_ADMIN, GUARDIAN and specific POD_VETO_ROLE
function veto(uint256 _podId, bytes32 proposalId)
/// @dev Permissioned to GOVERNOR, POD_VETO_ADMIN, GUARDIAN, POD_ADMIN and the specific
/// pod admin and guardian roles
function veto(uint256 _podId, bytes32 _proposalId)
external
override
hasAnyOfFourRoles(
hasAnyOfSixRoles(
TribeRoles.GOVERNOR,
TribeRoles.POD_VETO_ADMIN,
TribeRoles.GUARDIAN,
// TODO: Pod specific admin
// TODO: Global pod admin
getPodVetoRole(_podId)
TribeRoles.POD_ADMIN,
getSpecificPodGuardianRole(_podId),
getSpecificPodAdminRole(_podId)
)
{
address timelock = podFactory.getPodTimelock(_podId);
emit VetoTimelock(_podId, timelock);
TimelockController(payable(timelock)).cancel(proposalId);
address _podTimelock = podFactory.getPodTimelock(_podId);
emit VetoTimelock(_podId, _podTimelock, _proposalId);
TimelockController(payable(_podTimelock)).cancel(_proposalId);
}
}
Loading