{
  "language": "Solidity",
  "sources": {
    "@openzeppelin/contracts/access/IAccessControl.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     *\n     * _Available since v3.1._\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call, an admin role\n     * bearer except when using {AccessControl-_setupRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     */\n    function renounceRole(bytes32 role, address account) external;\n}\n"
    },
    "@venusprotocol/solidity-utilities/contracts/validators.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\nerror ZeroAddressNotAllowed();\n\n/// @notice Thrown if the supplied value is 0 where it is not allowed\nerror ZeroValueNotAllowed();\n\n/// @notice Checks if the provided address is nonzero, reverts otherwise\n/// @param address_ Address to check\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\nfunction ensureNonzeroAddress(address address_) pure {\n    if (address_ == address(0)) {\n        revert ZeroAddressNotAllowed();\n    }\n}\n\n/// @notice Checks if the provided value is nonzero, reverts otherwise\n/// @param value_ Value to check\n/// @custom:error ZeroValueNotAllowed is thrown if the provided value is 0\nfunction ensureNonzeroValue(uint256 value_) pure {\n    if (value_ == 0) {\n        revert ZeroValueNotAllowed();\n    }\n}\n"
    },
    "contracts/Governance/IAccessControlManagerV8.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/**\n * @title IAccessControlManagerV8\n * @author Venus\n * @notice Interface implemented by the `AccessControlManagerV8` contract.\n */\ninterface IAccessControlManagerV8 is IAccessControl {\n    function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n    function revokeCallPermission(\n        address contractAddress,\n        string calldata functionSig,\n        address accountToRevoke\n    ) external;\n\n    function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n    function hasPermission(\n        address account,\n        address contractAddress,\n        string calldata functionSig\n    ) external view returns (bool);\n}\n"
    },
    "contracts/Governance/TimelockV8.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title TimelockV8\n * @author Venus\n * @notice The Timelock contract using solidity V8.\n * This contract also differs from the original timelock because it has a virtual function to get minimum delays\n * and allow test deployments to override the value.\n */\ncontract TimelockV8 {\n    /// @notice Required period to execute a proposal transaction\n    uint256 private constant DEFAULT_GRACE_PERIOD = 14 days;\n\n    /// @notice Minimum amount of time a proposal transaction must be queued\n    uint256 private constant DEFAULT_MINIMUM_DELAY = 1 hours;\n\n    /// @notice Maximum amount of time a proposal transaction must be queued\n    uint256 private constant DEFAULT_MAXIMUM_DELAY = 30 days;\n\n    /// @notice Timelock admin authorized to queue and execute transactions\n    address public admin;\n\n    /// @notice Account proposed as the next admin\n    address public pendingAdmin;\n\n    /// @notice Period for a proposal transaction to be queued\n    uint256 public delay;\n\n    /// @notice Mapping of queued transactions\n    mapping(bytes32 => bool) public queuedTransactions;\n\n    /// @notice Event emitted when a new admin is accepted\n    event NewAdmin(address indexed oldAdmin, address indexed newAdmin);\n\n    /// @notice Event emitted when a new admin is proposed\n    event NewPendingAdmin(address indexed newPendingAdmin);\n\n    /// @notice Event emitted when a new delay is proposed\n    event NewDelay(uint256 indexed oldDelay, uint256 indexed newDelay);\n\n    /// @notice Event emitted when a proposal transaction has been cancelled\n    event CancelTransaction(\n        bytes32 indexed txHash,\n        address indexed target,\n        uint256 value,\n        string signature,\n        bytes data,\n        uint256 eta\n    );\n\n    /// @notice Event emitted when a proposal transaction has been executed\n    event ExecuteTransaction(\n        bytes32 indexed txHash,\n        address indexed target,\n        uint256 value,\n        string signature,\n        bytes data,\n        uint256 eta\n    );\n\n    /// @notice Event emitted when a proposal transaction has been queued\n    event QueueTransaction(\n        bytes32 indexed txHash,\n        address indexed target,\n        uint256 value,\n        string signature,\n        bytes data,\n        uint256 eta\n    );\n\n    constructor(address admin_, uint256 delay_) {\n        require(delay_ >= MINIMUM_DELAY(), \"Timelock::constructor: Delay must exceed minimum delay.\");\n        require(delay_ <= MAXIMUM_DELAY(), \"Timelock::setDelay: Delay must not exceed maximum delay.\");\n        ensureNonzeroAddress(admin_);\n\n        admin = admin_;\n        delay = delay_;\n    }\n\n    fallback() external payable {}\n\n    /**\n     * @notice Setter for the transaction queue delay\n     * @param delay_ The new delay period for the transaction queue\n     * @custom:access Sender must be Timelock itself\n     * @custom:event Emit NewDelay with old and new delay\n     */\n    function setDelay(uint256 delay_) public {\n        require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n        require(delay_ >= MINIMUM_DELAY(), \"Timelock::setDelay: Delay must exceed minimum delay.\");\n        require(delay_ <= MAXIMUM_DELAY(), \"Timelock::setDelay: Delay must not exceed maximum delay.\");\n        emit NewDelay(delay, delay_);\n        delay = delay_;\n    }\n\n    /**\n     * @notice Return grace period\n     * @return The duration of the grace period, specified as a uint256 value.\n     */\n    function GRACE_PERIOD() public view virtual returns (uint256) {\n        return DEFAULT_GRACE_PERIOD;\n    }\n\n    /**\n     * @notice Return required minimum delay\n     * @return Minimum delay\n     */\n    function MINIMUM_DELAY() public view virtual returns (uint256) {\n        return DEFAULT_MINIMUM_DELAY;\n    }\n\n    /**\n     * @notice Return required maximum delay\n     * @return Maximum delay\n     */\n    function MAXIMUM_DELAY() public view virtual returns (uint256) {\n        return DEFAULT_MAXIMUM_DELAY;\n    }\n\n    /**\n     * @notice Method for accepting a proposed admin\n     * @custom:access Sender must be pending admin\n     * @custom:event Emit NewAdmin with old and new admin\n     */\n    function acceptAdmin() public {\n        require(msg.sender == pendingAdmin, \"Timelock::acceptAdmin: Call must come from pendingAdmin.\");\n        emit NewAdmin(admin, msg.sender);\n        admin = msg.sender;\n        pendingAdmin = address(0);\n    }\n\n    /**\n     * @notice Method to propose a new admin authorized to call timelock functions. This should be the Governor Contract\n     * @param pendingAdmin_ Address of the proposed admin\n     * @custom:access Sender must be Timelock contract itself or admin\n     * @custom:event Emit NewPendingAdmin with new pending admin\n     */\n    function setPendingAdmin(address pendingAdmin_) public {\n        require(\n            msg.sender == address(this) || msg.sender == admin,\n            \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n        );\n        ensureNonzeroAddress(pendingAdmin_);\n        pendingAdmin = pendingAdmin_;\n\n        emit NewPendingAdmin(pendingAdmin);\n    }\n\n    /**\n     * @notice Called for each action when queuing a proposal\n     * @param target Address of the contract with the method to be called\n     * @param value Native token amount sent with the transaction\n     * @param signature Signature of the function to be called\n     * @param data Arguments to be passed to the function when called\n     * @param eta Timestamp after which the transaction can be executed\n     * @return Hash of the queued transaction\n     * @custom:access Sender must be admin\n     * @custom:event Emit QueueTransaction\n     */\n    function queueTransaction(\n        address target,\n        uint256 value,\n        string calldata signature,\n        bytes calldata data,\n        uint256 eta\n    ) public returns (bytes32) {\n        require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n        require(\n            eta >= getBlockTimestamp() + delay,\n            \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n        );\n\n        bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n        require(!queuedTransactions[txHash], \"Timelock::queueTransaction: transaction already queued.\");\n        queuedTransactions[txHash] = true;\n\n        emit QueueTransaction(txHash, target, value, signature, data, eta);\n        return txHash;\n    }\n\n    /**\n     * @notice Called to cancel a queued transaction\n     * @param target Address of the contract with the method to be called\n     * @param value Native token amount sent with the transaction\n     * @param signature Signature of the function to be called\n     * @param data Arguments to be passed to the function when called\n     * @param eta Timestamp after which the transaction can be executed\n     * @custom:access Sender must be admin\n     * @custom:event Emit CancelTransaction\n     */\n    function cancelTransaction(\n        address target,\n        uint256 value,\n        string calldata signature,\n        bytes calldata data,\n        uint256 eta\n    ) public {\n        require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n        bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n        require(queuedTransactions[txHash], \"Timelock::cancelTransaction: transaction is not queued yet.\");\n        delete (queuedTransactions[txHash]);\n\n        emit CancelTransaction(txHash, target, value, signature, data, eta);\n    }\n\n    /**\n     * @notice Called to execute a queued transaction\n     * @param target Address of the contract with the method to be called\n     * @param value Native token amount sent with the transaction\n     * @param signature Signature of the function to be called\n     * @param data Arguments to be passed to the function when called\n     * @param eta Timestamp after which the transaction can be executed\n     * @return Result of function call\n     * @custom:access Sender must be admin\n     * @custom:event Emit ExecuteTransaction\n     */\n    function executeTransaction(\n        address target,\n        uint256 value,\n        string calldata signature,\n        bytes calldata data,\n        uint256 eta\n    ) public returns (bytes memory) {\n        require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n        bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n        require(queuedTransactions[txHash], \"Timelock::executeTransaction: Transaction hasn't been queued.\");\n        require(getBlockTimestamp() >= eta, \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\");\n        require(getBlockTimestamp() <= eta + GRACE_PERIOD(), \"Timelock::executeTransaction: Transaction is stale.\");\n\n        delete (queuedTransactions[txHash]);\n\n        bytes memory callData;\n\n        if (bytes(signature).length == 0) {\n            callData = data;\n        } else {\n            callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n        }\n\n        // solium-disable-next-line security/no-call-value\n        (bool success, bytes memory returnData) = target.call{ value: value }(callData);\n        require(success, \"Timelock::executeTransaction: Transaction execution reverted.\");\n\n        emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n        return returnData;\n    }\n\n    /**\n     * @notice Returns the current block timestamp\n     * @return The current block timestamp\n     */\n    function getBlockTimestamp() internal view returns (uint256) {\n        // solium-disable-next-line security/no-block-members\n        return block.timestamp;\n    }\n}\n"
    },
    "contracts/test/TestTimelockV8.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport { TimelockV8 } from \"../Governance/TimelockV8.sol\";\n\ncontract TestTimelockV8 is TimelockV8 {\n    constructor(address admin_, uint256 delay_) public TimelockV8(admin_, delay_) {}\n\n    function GRACE_PERIOD() public view override returns (uint256) {\n        return 1 hours;\n    }\n\n    function MINIMUM_DELAY() public view override returns (uint256) {\n        return 1;\n    }\n\n    function MAXIMUM_DELAY() public view override returns (uint256) {\n        return 1 hours;\n    }\n}\n"
    },
    "contracts/Utils/ACMCommandsAggregator.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { IAccessControlManagerV8 } from \"../Governance/IAccessControlManagerV8.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title ACMCommandsAggregator\n * @author Venus\n * @notice This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.\n */\ncontract ACMCommandsAggregator {\n    /*\n     * @notice Struct to store permission details\n     */\n    struct Permission {\n        /*\n         * @notice Address of the contract\n         */\n        address contractAddress;\n        /*\n         * @notice Function signature\n         */\n        string functionSig;\n        /*\n         * @notice Address of the account\n         */\n        address account;\n    }\n\n    /**\n     * @notice Access control manager contract\n     */\n    IAccessControlManagerV8 public immutable ACM;\n\n    /*\n     * @notice 2D array to store grant permissions in batches\n     */\n    Permission[][] public grantPermissions;\n\n    /*\n     * @notice 2D array to store revoke permissions in batches\n     */\n    Permission[][] public revokePermissions;\n\n    /*\n     * @notice Event emitted when grant permissions are added\n     */\n    event GrantPermissionsAdded(uint256 index);\n\n    /*\n     * @notice Event emitted when revoke permissions are added\n     */\n    event RevokePermissionsAdded(uint256 index);\n\n    /*\n     * @notice Event emitted when grant permissions are executed\n     */\n    event GrantPermissionsExecuted(uint256 index);\n\n    /*\n     * @notice Event emitted when revoke permissions are executed\n     */\n    event RevokePermissionsExecuted(uint256 index);\n\n    /*\n     * @notice Error to be thrown when permissions are empty\n     */\n    error EmptyPermissions();\n\n    /*\n     * @notice Constructor to set the access control manager\n     * @param _acm Address of the access control manager\n     */\n    constructor(IAccessControlManagerV8 _acm) {\n        ensureNonzeroAddress(address(_acm));\n        ACM = _acm;\n    }\n\n    /*\n     * @notice Function to add grant permissions\n     * @param _permissions Array of permissions\n     * @custom:event Emits GrantPermissionsAdded event\n     */\n    function addGrantPermissions(Permission[] memory _permissions) external {\n        if (_permissions.length == 0) {\n            revert EmptyPermissions();\n        }\n\n        uint256 index = grantPermissions.length;\n        grantPermissions.push();\n\n        for (uint256 i; i < _permissions.length; ++i) {\n            grantPermissions[index].push(\n                Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\n            );\n        }\n\n        emit GrantPermissionsAdded(index);\n    }\n\n    /*\n     * @notice Function to add revoke permissions\n     * @param _permissions Array of permissions\n     * @custom:event Emits RevokePermissionsAdded event\n     */\n    function addRevokePermissions(Permission[] memory _permissions) external {\n        if (_permissions.length == 0) {\n            revert EmptyPermissions();\n        }\n\n        uint256 index = revokePermissions.length;\n        revokePermissions.push();\n\n        for (uint256 i; i < _permissions.length; ++i) {\n            revokePermissions[index].push(\n                Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\n            );\n        }\n\n        emit RevokePermissionsAdded(index);\n    }\n\n    /*\n     * @notice Function to execute grant permissions\n     * @param index Index of the permissions array\n     * @custom:event Emits GrantPermissionsExecuted event\n     */\n    function executeGrantPermissions(uint256 index) external {\n        uint256 length = grantPermissions[index].length;\n        for (uint256 i; i < length; ++i) {\n            Permission memory permission = grantPermissions[index][i];\n            ACM.giveCallPermission(permission.contractAddress, permission.functionSig, permission.account);\n        }\n\n        emit GrantPermissionsExecuted(index);\n    }\n\n    /*\n     * @notice Function to execute revoke permissions\n     * @param index Index of the permissions array\n     * @custom:event Emits RevokePermissionsExecuted event\n     */\n    function executeRevokePermissions(uint256 index) external {\n        uint256 length = revokePermissions[index].length;\n        for (uint256 i; i < length; ++i) {\n            Permission memory permission = revokePermissions[index][i];\n            ACM.revokeCallPermission(permission.contractAddress, permission.functionSig, permission.account);\n        }\n\n        emit RevokePermissionsExecuted(index);\n    }\n}\n"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 10000
    },
    "evmVersion": "paris",
    "outputSelection": {
      "*": {
        "*": [
          "storageLayout",
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata",
          "devdoc",
          "userdoc",
          "evm.gasEstimates"
        ],
        "": ["ast"]
      }
    },
    "metadata": {
      "useLiteralContent": true
    }
  }
}
