Skip to content

Commit

Permalink
Adding Contracts for compilation and change to return result
Browse files Browse the repository at this point in the history
  • Loading branch information
mustermeiszer committed Jul 7, 2023
1 parent 781d2d5 commit c5e02ad
Show file tree
Hide file tree
Showing 59 changed files with 4,031 additions and 155 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import { EternalStorage } from './EternalStorage.sol';

/*
* Deprecated. See InterchainGovernance instead.
* AxelarGateway still inherits this to preserve storage layout used by EternalStorage when upgrading.
*/
contract AdminMultisigBase is EternalStorage {
error NotAdmin();
error AlreadyVoted();
error InvalidAdmins();
error InvalidAdminThreshold();
error DuplicateAdmin(address admin);

// AUDIT: slot names should be prefixed with some standard string
bytes32 internal constant KEY_ADMIN_EPOCH = keccak256('admin-epoch');

bytes32 internal constant PREFIX_ADMIN = keccak256('admin');
bytes32 internal constant PREFIX_ADMIN_COUNT = keccak256('admin-count');
bytes32 internal constant PREFIX_ADMIN_THRESHOLD = keccak256('admin-threshold');
bytes32 internal constant PREFIX_ADMIN_VOTE_COUNTS = keccak256('admin-vote-counts');
bytes32 internal constant PREFIX_ADMIN_VOTED = keccak256('admin-voted');
bytes32 internal constant PREFIX_IS_ADMIN = keccak256('is-admin');

// NOTE: Given the early void return, this modifier should be used with care on functions that return data.
modifier onlyAdmin() {
uint256 adminEpoch = _adminEpoch();

if (!_isAdmin(adminEpoch, msg.sender)) revert NotAdmin();

bytes32 topic = keccak256(msg.data);

// Check that admin has not voted, then record that they have voted.
if (_hasVoted(adminEpoch, topic, msg.sender)) revert AlreadyVoted();

_setHasVoted(adminEpoch, topic, msg.sender, true);

// Determine the new vote count and update it.
uint256 adminVoteCount = _getVoteCount(adminEpoch, topic) + uint256(1);
_setVoteCount(adminEpoch, topic, adminVoteCount);

// Do not proceed with operation execution if insufficient votes.
if (adminVoteCount < _getAdminThreshold(adminEpoch)) return;

_;

// Clear vote count and voted booleans.
_setVoteCount(adminEpoch, topic, uint256(0));

uint256 adminCount = _getAdminCount(adminEpoch);

for (uint256 i; i < adminCount; ++i) {
_setHasVoted(adminEpoch, topic, _getAdmin(adminEpoch, i), false);
}
}

/********************\
|* Pure Key Getters *|
\********************/

function _getAdminKey(uint256 adminEpoch, uint256 index) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(PREFIX_ADMIN, adminEpoch, index));
}

function _getAdminCountKey(uint256 adminEpoch) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(PREFIX_ADMIN_COUNT, adminEpoch));
}

function _getAdminThresholdKey(uint256 adminEpoch) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(PREFIX_ADMIN_THRESHOLD, adminEpoch));
}

function _getAdminVoteCountsKey(uint256 adminEpoch, bytes32 topic) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(PREFIX_ADMIN_VOTE_COUNTS, adminEpoch, topic));
}

function _getAdminVotedKey(
uint256 adminEpoch,
bytes32 topic,
address account
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(PREFIX_ADMIN_VOTED, adminEpoch, topic, account));
}

function _getIsAdminKey(uint256 adminEpoch, address account) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(PREFIX_IS_ADMIN, adminEpoch, account));
}

/***********\
|* Getters *|
\***********/

function _adminEpoch() internal view returns (uint256) {
return getUint(KEY_ADMIN_EPOCH);
}

function _getAdmin(uint256 adminEpoch, uint256 index) internal view returns (address) {
return getAddress(_getAdminKey(adminEpoch, index));
}

function _getAdminCount(uint256 adminEpoch) internal view returns (uint256) {
return getUint(_getAdminCountKey(adminEpoch));
}

function _getAdminThreshold(uint256 adminEpoch) internal view returns (uint256) {
return getUint(_getAdminThresholdKey(adminEpoch));
}

function _getVoteCount(uint256 adminEpoch, bytes32 topic) internal view returns (uint256) {
return getUint(_getAdminVoteCountsKey(adminEpoch, topic));
}

function _hasVoted(
uint256 adminEpoch,
bytes32 topic,
address account
) internal view returns (bool) {
return getBool(_getAdminVotedKey(adminEpoch, topic, account));
}

function _isAdmin(uint256 adminEpoch, address account) internal view returns (bool) {
return getBool(_getIsAdminKey(adminEpoch, account));
}

/***********\
|* Setters *|
\***********/

function _setAdminEpoch(uint256 adminEpoch) internal {
_setUint(KEY_ADMIN_EPOCH, adminEpoch);
}

function _setAdmin(
uint256 adminEpoch,
uint256 index,
address account
) internal {
_setAddress(_getAdminKey(adminEpoch, index), account);
}

function _setAdminCount(uint256 adminEpoch, uint256 adminCount) internal {
_setUint(_getAdminCountKey(adminEpoch), adminCount);
}

function _setAdmins(
uint256 adminEpoch,
address[] memory accounts,
uint256 threshold
) internal {
uint256 adminLength = accounts.length;

if (adminLength < threshold) revert InvalidAdmins();

if (threshold == uint256(0)) revert InvalidAdminThreshold();

_setAdminThreshold(adminEpoch, threshold);
_setAdminCount(adminEpoch, adminLength);

for (uint256 i; i < adminLength; ++i) {
address account = accounts[i];

// Check that the account wasn't already set as an admin for this epoch.
if (_isAdmin(adminEpoch, account)) revert DuplicateAdmin(account);

if (account == address(0)) revert InvalidAdmins();

// Set this account as the i-th admin in this epoch (needed to we can clear topic votes in `onlyAdmin`).
_setAdmin(adminEpoch, i, account);
_setIsAdmin(adminEpoch, account, true);
}
}

function _setAdminThreshold(uint256 adminEpoch, uint256 adminThreshold) internal {
_setUint(_getAdminThresholdKey(adminEpoch), adminThreshold);
}

function _setVoteCount(
uint256 adminEpoch,
bytes32 topic,
uint256 voteCount
) internal {
_setUint(_getAdminVoteCountsKey(adminEpoch, topic), voteCount);
}

function _setHasVoted(
uint256 adminEpoch,
bytes32 topic,
address account,
bool voted
) internal {
_setBool(_getAdminVotedKey(adminEpoch, topic, account), voted);
}

function _setIsAdmin(
uint256 adminEpoch,
address account,
bool isAdmin
) internal {
_setBool(_getIsAdminKey(adminEpoch, account), isAdmin);
}
}
Loading

0 comments on commit c5e02ad

Please sign in to comment.