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

Add PodAdmin gateway - expose admin fns and veto #587

Merged
merged 39 commits into from
Mar 23, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
9731910
feat: add multiPodAdmin contract
thomas-waite Mar 15, 2022
500124e
test: setup of MultiPodAdmin tests
thomas-waite Mar 15, 2022
421c45a
test: test add pod member
thomas-waite Mar 15, 2022
515979a
test: add remove admin test
thomas-waite Mar 15, 2022
30d6bcf
refactor: transfer admin management to role rather than address
thomas-waite Mar 16, 2022
34af7aa
test: migrate tests to role based management
thomas-waite Mar 16, 2022
f78f201
refactor: delineate admin priviledges, make granular
thomas-waite Mar 16, 2022
d08dc86
test: add admin priviledg delineation tests
thomas-waite Mar 16, 2022
103fc41
Merge branch 'feat-governance-upgrade' into feat-multiple-pod-admins
thomas-waite Mar 16, 2022
f2eb757
feat: add multipod admin into setup deploy script
thomas-waite Mar 16, 2022
01e026b
refactor: add batch member add and remove fns
thomas-waite Mar 16, 2022
3c4bb5d
refactor: update dao script to use multiPodAdmin
thomas-waite Mar 16, 2022
d74b3b5
test: update e2e tests to use multiPodAdmin
thomas-waite Mar 16, 2022
7f9f80c
refactor: rename to PodAdminGateway
thomas-waite Mar 16, 2022
2150be1
refactor: consolidate into config, add veto controller option
thomas-waite Mar 17, 2022
0ff8999
feat: add VetoController
thomas-waite Mar 17, 2022
d53d1ec
test: setup tests for vetoController
thomas-waite Mar 17, 2022
7a1f484
test: validate nominated VetoController can cancel on timelock
thomas-waite Mar 17, 2022
890a7c1
feat: add validate veto permission
thomas-waite Mar 17, 2022
3b7c173
test: add test for pod deployer role
thomas-waite Mar 18, 2022
dfdc4db
refactor: update DAO script to assign various roles
thomas-waite Mar 18, 2022
3f1d81e
refactor: gas optimisation, more tests
thomas-waite Mar 18, 2022
800d9c5
feat: add pod veto admin role
thomas-waite Mar 18, 2022
4a180b5
refactor: adjust deploy script to include roles
thomas-waite Mar 18, 2022
1ee2708
refactor: minor fixes
thomas-waite Mar 21, 2022
a334744
refactor: update permission mapping
thomas-waite Mar 21, 2022
cf53b56
Merge branch 'feat-role-arch-veto' into feat-multiple-pod-admins
thomas-waite Mar 21, 2022
7d8c13a
fix: correct broken merge
thomas-waite Mar 21, 2022
2b86120
refactor: implement PR feedback, gas optimisations
thomas-waite Mar 21, 2022
a4f36d4
refactor: move to deterministic role based auth
thomas-waite Mar 21, 2022
4704306
refactor: move to deterministic role model
thomas-waite Mar 22, 2022
1edaf07
test: migrate tests
thomas-waite Mar 22, 2022
1052d17
refactor: put pod veto functionality on gateway
thomas-waite Mar 22, 2022
58e0b6b
refactor: improve access control
thomas-waite Mar 22, 2022
5be4401
refactor: update fip script
thomas-waite Mar 22, 2022
916b9c3
refactor: permissions cleanup
thomas-waite Mar 22, 2022
bb80e94
feat: add pod admin transfer functionality
thomas-waite Mar 22, 2022
82b1613
refactor: cleanup
thomas-waite Mar 22, 2022
145ba26
feat: gas optimisations
thomas-waite Mar 23, 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
21 changes: 21 additions & 0 deletions contracts/pods/IPodAdminGateway.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

interface IPodAdminGateway {
error UnauthorisedAdminAction();

event GrantPodAdminPriviledge(
uint256 indexed podId,
bytes32 indexed tribeRole
);
event RevokePodAdminPriviledge(
uint256 indexed podId,
bytes32 indexed tribeRole
);

/// @notice Delineated admin priviledges available to the admin of an Orca pod
enum AdminPriviledge {
ADD_MEMBER,
REMOVE_MEMBER
}
}
179 changes: 179 additions & 0 deletions contracts/pods/PodAdminGateway.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {IMemberToken} from "./orcaInterfaces/IMemberToken.sol";
import {CoreRef} from "../refs/CoreRef.sol";
import {ICore} from "../core/ICore.sol";
import {TribeRoles} from "../core/TribeRoles.sol";
import {IPodAdminGateway} from "./IPodAdminGateway.sol";

/// @title Multiple Pod Admins for Orca pods
/// @notice Expose pod admin functionality from Orca pods to multiple Tribe Roles.
/// @dev This contract is intended to be granted the podAdmin role on a deployed pod. This
/// contract then maintains it's own internal state of additional TribeRoles that it will
/// expose podAdmin actions to.
/// In this way, multiple podAdmins can be added per pod.
contract PodAdminGateway is CoreRef, IPodAdminGateway {
using EnumerableSet for EnumerableSet.Bytes32Set;

/// @notice Orca membership token for the pods. Handles permissioning pod members
IMemberToken private immutable memberToken;

/// @notice Mapping from a podId to an admin priviledge and the set of TribeRoles that have
/// been granted that admin priviledge on that pod
/// @dev Used to permission the exposure of pod admin priviledges to multiple TribeRoles
mapping(uint256 => mapping(AdminPriviledge => EnumerableSet.Bytes32Set))
private podAdminRoles;

constructor(address _core, address _memberToken) CoreRef(_core) {
memberToken = IMemberToken(_memberToken);
}

///////////////////////// GETTERS ///////////////////////

/// @notice Get all TribeRoles which have a particular admin priviledge on a pod
function getPodAdminPriviledges(uint256 _podId, AdminPriviledge _priviledge)
external
view
returns (bytes32[] memory)
{
if (podAdminRoles[_podId][_priviledge].length() == 0) {
bytes32[] memory emptyAdmins = new bytes32[](0);
return emptyAdmins;
}
return podAdminRoles[_podId][_priviledge].values();
}

///////////////////////// STATE CHANGING API ////////////////////////////

///// Grant and revoke pod admin functionality to Tribe Roles

/// @notice Grant an admin priviledge to a TribeRole
/// @dev Permissioned to the GOVERNOR, ROLE_ADMIN (TribalCouncil)
function grantPodAdminPriviledge(
uint256 _podId,
AdminPriviledge priviledge,
bytes32 _tribeRole
) public hasAnyOfTwoRoles(TribeRoles.GOVERNOR, TribeRoles.ROLE_ADMIN) {
podAdminRoles[_podId][priviledge].add(_tribeRole);
emit GrantPodAdminPriviledge(_podId, _tribeRole);
}

/// @notice Revoke an admin priviledge from a TribeRole
/// @dev Permissioned to the GOVERNOR, ROLE_ADMIN (TribalCouncil) and GUARDIAN roles
function revokePodAdminPriviledge(
uint256 _podId,
AdminPriviledge priviledge,
bytes32 _tribeRole
)
public
hasAnyOfThreeRoles(
TribeRoles.GOVERNOR,
TribeRoles.ROLE_ADMIN,
TribeRoles.GUARDIAN
)
{
podAdminRoles[_podId][priviledge].remove(_tribeRole);
emit RevokePodAdminPriviledge(_podId, _tribeRole);
}

/// @notice Batch grant admin priviledges
function batchGrantAdminPriviledge(
uint256[] memory _podId,
AdminPriviledge[] memory priviledge,
bytes32[] memory _tribeRole
) external hasAnyOfTwoRoles(TribeRoles.GOVERNOR, TribeRoles.ROLE_ADMIN) {
for (uint256 i = 0; i < _podId.length; i++) {
grantPodAdminPriviledge(_podId[i], priviledge[i], _tribeRole[i]);
}
}

/// @notice Batch grant admin priviledges
function batchRevokeAdminPriviledge(
uint256[] memory _podId,
AdminPriviledge[] memory priviledge,
bytes32[] memory _tribeRole
)
external
hasAnyOfThreeRoles(
TribeRoles.GOVERNOR,
TribeRoles.ROLE_ADMIN,
thomas-waite marked this conversation as resolved.
Show resolved Hide resolved
TribeRoles.GUARDIAN
)
{
for (uint256 i = 0; i < _podId.length; i++) {
revokePodAdminPriviledge(_podId[i], priviledge[i], _tribeRole[i]);
}
}

///// Expose admin functionality to addresses which have the appropriate TribeRole

/// @notice Admin functionality to add a member to a pod
function addMemberToPod(uint256 _podId, address _member) public {
require(_member != address(0), "ZERO_ADDRESS");
validateAdminPriviledge(_podId, AdminPriviledge.ADD_MEMBER, msg.sender);

memberToken.mint(_member, _podId, bytes(""));
}

/// @notice Admin functionality to batch add a member to a pod
function batchAddMemberToPod(uint256 _podId, address[] memory _members)
external
{
for (uint256 i = 0; i < _members.length; i++) {
addMemberToPod(_podId, _members[i]);
}
}

/// @notice Admin functionality to remove a member from a pod
function removeMemberFromPod(uint256 _podId, address _member) public {
require(_member != address(0), "ZERO_ADDRESS");

validateAdminPriviledge(
_podId,
AdminPriviledge.REMOVE_MEMBER,
msg.sender
);
memberToken.burn(_member, _podId);
}

/// @notice Admin functionality to batch remove a member from a pod
function batchRemoveMemberFromPod(uint256 _podId, address[] memory _members)
external
{
for (uint256 i = 0; i < _members.length; i++) {
removeMemberFromPod(_podId, _members[i]);
}
}

/// @notice Valdidate that a calling address has the relevant admin priviledge, for the
/// function it is calling
function validateAdminPriviledge(
thomas-waite marked this conversation as resolved.
Show resolved Hide resolved
uint256 _podId,
AdminPriviledge priviledge,
address caller
) internal view {
ICore core = core();
bool hasAdminRole = false;

// Iterate through all TribeRoles that have correct priviledge.
// Validate caller has one of these roles
// podAdminRoles[_podId][priviledge] = tribeRolesWithPriviledge
for (
uint256 i = 0;
i < podAdminRoles[_podId][priviledge].length();
thomas-waite marked this conversation as resolved.
Show resolved Hide resolved
i += 1
thomas-waite marked this conversation as resolved.
Show resolved Hide resolved
) {
bytes32 role = podAdminRoles[_podId][priviledge].at(i);

if (core.hasRole(role, caller)) {
hasAdminRole = true;
}
}

if (!hasAdminRole) {
revert UnauthorisedAdminAction();
}
}
}
1 change: 1 addition & 0 deletions contracts/pods/PodFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ contract PodFactory is CoreRef, IPodFactory {
//////////////////// STATE-CHANGING API ////////////////////

/// @notice Create a child Orca pod with optimistic timelock. Callable by the DAO and the Tribal Council
/// @dev Returns podId and the optimistic timelock address
function createChildOptimisticPod(
PodConfig calldata _config,
uint256 minDelay
Expand Down
1 change: 0 additions & 1 deletion contracts/test/integration/fixtures/Orca.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {IInviteToken} from "../../../pods/orcaInterfaces/IInviteToken.sol";
import {IPodFactory} from "../../../pods/IPodFactory.sol";
import {OptimisticTimelock} from "../../../dao/timelock/OptimisticTimelock.sol";
import {Vm} from "../../utils/Vm.sol";
import "hardhat/console.sol";

function createPod(
IControllerV1 controller,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {IMemberToken} from "../../../pods/orcaInterfaces/IMemberToken.sol";
import {createPod, setupOptimisticTimelock, mintOrcaTokens} from "../fixtures/Orca.sol";
import {Vm} from "../../utils/Vm.sol";
import {DSTest} from "../../utils/DSTest.sol";
import "hardhat/console.sol";

/// @dev Tests for the optimistic governance pod unit. This is composed of an
/// Orca pod and an optimistic timelock. Key agents involved are:
Expand Down
Loading