UNPKG

@venusprotocol/governance-contracts

Version:

### Prerequisites

65 lines (64 loc) 44.7 kB
{ "language": "Solidity", "sources": { "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroEndpoint.sol": { "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\nimport \"./ILayerZeroUserApplicationConfig.sol\";\n\ninterface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {\n // @notice send a LayerZero message to the specified address at a LayerZero endpoint.\n // @param _dstChainId - the destination chain identifier\n // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains\n // @param _payload - a custom bytes payload to send to the destination contract\n // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address\n // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction\n // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination\n function send(\n uint16 _dstChainId,\n bytes calldata _destination,\n bytes calldata _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes calldata _adapterParams\n ) external payable;\n\n // @notice used by the messaging library to publish verified payload\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source contract (as bytes) at the source chain\n // @param _dstAddress - the address on destination chain\n // @param _nonce - the unbound message ordering nonce\n // @param _gasLimit - the gas limit for external contract execution\n // @param _payload - verified payload to send to the destination contract\n function receivePayload(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n address _dstAddress,\n uint64 _nonce,\n uint _gasLimit,\n bytes calldata _payload\n ) external;\n\n // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);\n\n // @notice get the outboundNonce from this source chain which, consequently, is always an EVM\n // @param _srcAddress - the source chain contract address\n function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);\n\n // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery\n // @param _dstChainId - the destination chain identifier\n // @param _userApplication - the user app address on this EVM chain\n // @param _payload - the custom message to send over LayerZero\n // @param _payInZRO - if false, user app pays the protocol fee in native token\n // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain\n function estimateFees(\n uint16 _dstChainId,\n address _userApplication,\n bytes calldata _payload,\n bool _payInZRO,\n bytes calldata _adapterParam\n ) external view returns (uint nativeFee, uint zroFee);\n\n // @notice get this Endpoint's immutable source identifier\n function getChainId() external view returns (uint16);\n\n // @notice the interface to retry failed message on this Endpoint destination\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n // @param _payload - the payload to be retried\n function retryPayload(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n bytes calldata _payload\n ) external;\n\n // @notice query if any STORED payload (message blocking) at the endpoint.\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);\n\n // @notice query if the _libraryAddress is valid for sending msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getSendLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the _libraryAddress is valid for receiving msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getReceiveLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the non-reentrancy guard for send() is on\n // @return true if the guard is on. false otherwise\n function isSendingPayload() external view returns (bool);\n\n // @notice query if the non-reentrancy guard for receive() is on\n // @return true if the guard is on. false otherwise\n function isReceivingPayload() external view returns (bool);\n\n // @notice get the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _userApplication - the contract address of the user application\n // @param _configType - type of configuration. every messaging library has its own convention.\n function getConfig(\n uint16 _version,\n uint16 _chainId,\n address _userApplication,\n uint _configType\n ) external view returns (bytes memory);\n\n // @notice get the send() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getSendVersion(address _userApplication) external view returns (uint16);\n\n // @notice get the lzReceive() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getReceiveVersion(address _userApplication) external view returns (uint16);\n}\n" }, "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroUserApplicationConfig.sol": { "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\ninterface ILayerZeroUserApplicationConfig {\n // @notice set the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _configType - type of configuration. every messaging library has its own convention.\n // @param _config - configuration in the bytes. can encode arbitrary content.\n function setConfig(\n uint16 _version,\n uint16 _chainId,\n uint _configType,\n bytes calldata _config\n ) external;\n\n // @notice set the send() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setSendVersion(uint16 _version) external;\n\n // @notice set the lzReceive() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setReceiveVersion(uint16 _version) external;\n\n // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload\n // @param _srcChainId - the chainId of the source chain\n // @param _srcAddress - the contract address of the source contract at the source chain\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;\n}\n" }, "@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" }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "@openzeppelin/contracts/security/Pausable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state.\n */\n constructor() {\n _paused = false;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n _requireNotPaused();\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n _requirePaused();\n _;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Throws if the contract is paused.\n */\n function _requireNotPaused() internal view virtual {\n require(!paused(), \"Pausable: paused\");\n }\n\n /**\n * @dev Throws if the contract is not paused.\n */\n function _requirePaused() internal view virtual {\n require(paused(), \"Pausable: not paused\");\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" }, "@openzeppelin/contracts/security/ReentrancyGuard.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor() {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\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/Cross-chain/BaseOmnichainControllerSrc.sol": { "content": "// SPDX-License-Identifier: BSD-3-Clause\n\npragma solidity 0.8.25;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { IAccessControlManagerV8 } from \"./../Governance/IAccessControlManagerV8.sol\";\n\n/**\n * @title BaseOmnichainControllerSrc\n * @dev This contract is the base for the Omnichain controller source contracts.\n * It provides functionality related to daily command limits and pausability.\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\ncontract BaseOmnichainControllerSrc is Ownable, Pausable {\n /**\n * @notice ACM (Access Control Manager) contract address\n */\n address public accessControlManager;\n\n /**\n * @notice Maximum daily limit for commands from the local chain\n */\n mapping(uint16 => uint256) public chainIdToMaxDailyLimit;\n\n /**\n * @notice Total commands transferred within the last 24-hour window from the local chain\n */\n mapping(uint16 => uint256) public chainIdToLast24HourCommandsSent;\n\n /**\n * @notice Timestamp when the last 24-hour window started from the local chain\n */\n mapping(uint16 => uint256) public chainIdToLast24HourWindowStart;\n /**\n * @notice Timestamp when the last proposal sent from the local chain to dest chain\n */\n mapping(uint16 => uint256) public chainIdToLastProposalSentTimestamp;\n\n /**\n * @notice Emitted when the maximum daily limit of commands from the local chain is modified\n */\n event SetMaxDailyLimit(uint16 indexed chainId, uint256 oldMaxLimit, uint256 newMaxLimit);\n /*\n * @notice Emitted when the address of ACM is updated\n */\n event NewAccessControlManager(address indexed oldAccessControlManager, address indexed newAccessControlManager);\n\n constructor(address accessControlManager_) {\n ensureNonzeroAddress(accessControlManager_);\n accessControlManager = accessControlManager_;\n }\n\n /**\n * @notice Sets the limit of daily (24 Hour) command amount\n * @param chainId_ Destination chain id\n * @param limit_ Number of commands\n * @custom:access Controlled by AccessControlManager\n * @custom:event Emits SetMaxDailyLimit with old and new limit and its corresponding chain id\n */\n function setMaxDailyLimit(uint16 chainId_, uint256 limit_) external {\n // _ensureAllowed(\"setMaxDailyLimit(uint16,uint256)\");\n emit SetMaxDailyLimit(chainId_, chainIdToMaxDailyLimit[chainId_], limit_);\n chainIdToMaxDailyLimit[chainId_] = limit_;\n }\n\n /**\n * @notice Triggers the paused state of the controller\n * @custom:access Controlled by AccessControlManager\n */\n function pause() external {\n // _ensureAllowed(\"pause()\");\n _pause();\n }\n\n /**\n * @notice Triggers the resume state of the controller\n * @custom:access Controlled by AccessControlManager\n */\n function unpause() external {\n // _ensureAllowed(\"unpause()\");\n _unpause();\n }\n\n /**\n * @notice Sets the address of Access Control Manager (ACM)\n * @param accessControlManager_ The new address of the Access Control Manager\n * @custom:access Only owner\n * @custom:event Emits NewAccessControlManager with old and new access control manager addresses\n */\n function setAccessControlManager(address accessControlManager_) external onlyOwner {\n ensureNonzeroAddress(accessControlManager_);\n emit NewAccessControlManager(accessControlManager, accessControlManager_);\n accessControlManager = accessControlManager_;\n }\n\n /**\n * @notice Empty implementation of renounce ownership to avoid any mishap\n */\n function renounceOwnership() public override {}\n\n /**\n * @notice Check eligibility to send commands\n * @param dstChainId_ Destination chain id\n * @param noOfCommands_ Number of commands to send\n */\n function _isEligibleToSend(uint16 dstChainId_, uint256 noOfCommands_) internal {\n // Load values for the 24-hour window checks\n uint256 currentBlockTimestamp = block.timestamp;\n uint256 lastDayWindowStart = chainIdToLast24HourWindowStart[dstChainId_];\n uint256 commandsSentInWindow = chainIdToLast24HourCommandsSent[dstChainId_];\n uint256 maxDailyLimit = chainIdToMaxDailyLimit[dstChainId_];\n uint256 lastProposalSentTimestamp = chainIdToLastProposalSentTimestamp[dstChainId_];\n\n // Check if the time window has changed (more than 24 hours have passed)\n if (currentBlockTimestamp - lastDayWindowStart > 1 days) {\n commandsSentInWindow = noOfCommands_;\n chainIdToLast24HourWindowStart[dstChainId_] = currentBlockTimestamp;\n } else {\n commandsSentInWindow += noOfCommands_;\n }\n\n // Revert if the amount exceeds the daily limit\n require(commandsSentInWindow <= maxDailyLimit, \"Daily Transaction Limit Exceeded\");\n // Revert if the last proposal is already sent in current block i.e multiple proposals cannot be sent within the same block.timestamp\n require(lastProposalSentTimestamp != currentBlockTimestamp, \"Multiple bridging in a proposal\");\n\n // Update the amount for the 24-hour window\n chainIdToLast24HourCommandsSent[dstChainId_] = commandsSentInWindow;\n // Update the last sent proposal timestamp\n chainIdToLastProposalSentTimestamp[dstChainId_] = currentBlockTimestamp;\n }\n\n // /**\n // * @notice Ensure that the caller has permission to execute a specific function\n // * @param functionSig_ Function signature to be checked for permission\n // */\n // function _ensureAllowed(string memory functionSig_) internal view {\n // require(\n // IAccessControlManagerV8(accessControlManager).isAllowedToCall(msg.sender, functionSig_),\n // \"access denied\"\n // );\n // }\n}\n" }, "contracts/Cross-chain/OmnichainProposalSender.sol": { "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.25;\n\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport { ILayerZeroEndpoint } from \"@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroEndpoint.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { BaseOmnichainControllerSrc } from \"./BaseOmnichainControllerSrc.sol\";\n\n/**\n * @title OmnichainProposalSender\n * @author Venus\n * @notice OmnichainProposalSender contract builds upon the functionality of its parent contract , BaseOmnichainControllerSrc\n * It sends a proposal's data to remote chains for execution after the proposal passes on the main chain\n * when used with GovernorBravo, the owner of this contract must be set to the Timelock contract\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\ncontract OmnichainProposalSender is ReentrancyGuard, BaseOmnichainControllerSrc {\n /**\n * @notice Stores the total number of remote proposals\n */\n uint256 public proposalCount;\n\n /**\n * @notice Execution hashes of failed messages\n * @dev [proposalId] -> [executionHash]\n */\n mapping(uint256 => bytes32) public storedExecutionHashes;\n\n /**\n * @notice LayerZero endpoint for sending messages to remote chains\n */\n ILayerZeroEndpoint public immutable LZ_ENDPOINT;\n\n /**\n * @notice Specifies the allowed path for sending messages (remote chainId => remote app address + local app address)\n */\n mapping(uint16 => bytes) public trustedRemoteLookup;\n\n /**\n * @notice Emitted when a remote message receiver is set for the remote chain\n */\n event SetTrustedRemoteAddress(uint16 indexed remoteChainId, bytes oldRemoteAddress, bytes newRemoteAddress);\n\n /**\n * @notice Event emitted when trusted remote sets to empty\n */\n event TrustedRemoteRemoved(uint16 indexed chainId);\n\n /**\n * @notice Emitted when a proposal execution request is sent to the remote chain\n */\n event ExecuteRemoteProposal(uint16 indexed remoteChainId, uint256 proposalId, bytes payload);\n\n /**\n * @notice Emitted when a previously failed message is successfully sent to the remote chain\n */\n event ClearPayload(uint256 indexed proposalId, bytes32 executionHash);\n\n /**\n * @notice Emitted when an execution hash of a failed message is saved\n */\n event StorePayload(\n uint256 indexed proposalId,\n uint16 indexed remoteChainId,\n bytes payload,\n bytes adapterParams,\n uint256 value,\n bytes reason\n );\n /**\n * @notice Emitted while fallback withdraw\n */\n event FallbackWithdraw(address indexed receiver, uint256 value);\n\n constructor(\n ILayerZeroEndpoint lzEndpoint_,\n address accessControlManager_\n ) BaseOmnichainControllerSrc(accessControlManager_) {\n ensureNonzeroAddress(address(lzEndpoint_));\n LZ_ENDPOINT = lzEndpoint_;\n }\n\n /**\n * @notice Estimates LayerZero fees for cross-chain message delivery to the remote chain\n * @dev The estimated fees are the minimum required; it's recommended to increase the fees amount when sending a message. The unused amount will be refunded\n * @param remoteChainId_ The LayerZero id of a remote chain\n * @param payload_ The payload to be sent to the remote chain. It's computed as follows:\n * payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param useZro_ Bool that indicates whether to pay in ZRO tokens or not\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @return nativeFee The amount of fee in the native gas token (e.g. ETH)\n * @return zroFee The amount of fee in ZRO token\n */\n function estimateFees(\n uint16 remoteChainId_,\n bytes calldata payload_,\n bool useZro_,\n bytes calldata adapterParams_\n ) external view returns (uint256, uint256) {\n return LZ_ENDPOINT.estimateFees(remoteChainId_, address(this), payload_, useZro_, adapterParams_);\n }\n\n /**\n * @notice Remove trusted remote from storage\n * @param remoteChainId_ The chain's id corresponds to setting the trusted remote to empty\n * @custom:access Controlled by Access Control Manager\n * @custom:event Emit TrustedRemoteRemoved with remote chain id\n */\n function removeTrustedRemote(uint16 remoteChainId_) external {\n // _ensureAllowed(\"removeTrustedRemote(uint16)\");\n require(trustedRemoteLookup[remoteChainId_].length != 0, \"OmnichainProposalSender: trusted remote not found\");\n delete trustedRemoteLookup[remoteChainId_];\n emit TrustedRemoteRemoved(remoteChainId_);\n }\n\n /**\n * @notice Sends a message to execute a remote proposal\n * @dev Stores the hash of the execution parameters if sending fails (e.g., due to insufficient fees)\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(targets, values, signatures, calldatas, proposalType)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param zroPaymentAddress_ The address of the ZRO token holder who would pay for the transaction. This must be either address(this) or tx.origin\n * @custom:event Emits ExecuteRemoteProposal with remote chain id, proposal ID and payload on success\n * @custom:event Emits StorePayload with last stored payload proposal ID ,remote chain id , payload, adapter params , values and reason for failure\n * @custom:access Controlled by Access Control Manager\n */\n function execute(\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n address zroPaymentAddress_\n ) external payable whenNotPaused {\n // _ensureAllowed(\"execute(uint16,bytes,bytes,address)\");\n\n // A zero value will result in a failed message; therefore, a positive value is required to send a message across the chain.\n require(msg.value > 0, \"OmnichainProposalSender: value cannot be zero\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n\n bytes memory trustedRemote = trustedRemoteLookup[remoteChainId_];\n require(trustedRemote.length != 0, \"OmnichainProposalSender: destination chain is not a trusted source\");\n _validateProposal(remoteChainId_, payload_);\n uint256 _pId = ++proposalCount;\n bytes memory payload = abi.encode(payload_, _pId);\n\n try\n LZ_ENDPOINT.send{ value: msg.value }(\n remoteChainId_,\n trustedRemote,\n payload,\n payable(msg.sender),\n zroPaymentAddress_,\n adapterParams_\n )\n {\n emit ExecuteRemoteProposal(remoteChainId_, _pId, payload);\n } catch (bytes memory reason) {\n storedExecutionHashes[_pId] = keccak256(abi.encode(remoteChainId_, payload, adapterParams_, msg.value));\n emit StorePayload(_pId, remoteChainId_, payload, adapterParams_, msg.value, reason);\n }\n }\n\n /**\n * @notice Resends a previously failed message\n * @dev Allows providing more fees if needed. The extra fees will be refunded to the caller\n * @param pId_ The proposal ID to identify a failed message\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param zroPaymentAddress_ The address of the ZRO token holder who would pay for the transaction.\n * @param originalValue_ The msg.value passed when execute() function was called\n * @custom:event Emits ClearPayload with proposal ID and hash\n * @custom:access Controlled by Access Control Manager\n */\n function retryExecute(\n uint256 pId_,\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n address zroPaymentAddress_,\n uint256 originalValue_\n ) external payable whenNotPaused nonReentrant {\n // _ensureAllowed(\"retryExecute(uint256,uint16,bytes,bytes,address,uint256)\");\n bytes memory trustedRemote = trustedRemoteLookup[remoteChainId_];\n require(trustedRemote.length != 0, \"OmnichainProposalSender: destination chain is not a trusted source\");\n bytes32 hash = storedExecutionHashes[pId_];\n require(hash != bytes32(0), \"OmnichainProposalSender: no stored payload\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n (bytes memory payload, ) = abi.decode(payload_, (bytes, uint256));\n _validateProposal(remoteChainId_, payload);\n\n require(\n keccak256(abi.encode(remoteChainId_, payload_, adapterParams_, originalValue_)) == hash,\n \"OmnichainProposalSender: invalid execution params\"\n );\n\n delete storedExecutionHashes[pId_];\n\n emit ClearPayload(pId_, hash);\n\n LZ_ENDPOINT.send{ value: originalValue_ + msg.value }(\n remoteChainId_,\n trustedRemote,\n payload_,\n payable(msg.sender),\n zroPaymentAddress_,\n adapterParams_\n );\n }\n\n /**\n * @notice Clear previously failed message\n * @param to_ Address of the receiver\n * @param pId_ The proposal ID to identify a failed message\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param originalValue_ The msg.value passed when execute() function was called\n * @custom:access Only owner\n * @custom:event Emits ClearPayload with proposal ID and hash\n * @custom:event Emits FallbackWithdraw with receiver and amount\n */\n function fallbackWithdraw(\n address to_,\n uint256 pId_,\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n uint256 originalValue_\n ) external onlyOwner nonReentrant {\n ensureNonzeroAddress(to_);\n require(originalValue_ > 0, \"OmnichainProposalSender: invalid native amount\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n\n bytes32 hash = storedExecutionHashes[pId_];\n require(hash != bytes32(0), \"OmnichainProposalSender: no stored payload\");\n\n bytes memory execution = abi.encode(remoteChainId_, payload_, adapterParams_, originalValue_);\n require(keccak256(execution) == hash, \"OmnichainProposalSender: invalid execution params\");\n\n delete storedExecutionHashes[pId_];\n\n emit FallbackWithdraw(to_, originalValue_);\n emit ClearPayload(pId_, hash);\n\n // Transfer the native to the `to_` address\n (bool sent, ) = to_.call{ value: originalValue_ }(\"\");\n require(sent, \"Call failed\");\n }\n\n /**\n * @notice Sets the remote message receiver address\n * @param remoteChainId_ The LayerZero id of a remote chain\n * @param newRemoteAddress_ The address of the contract on the remote chain to receive messages sent by this contract\n * @custom:access Controlled by AccessControlManager\n * @custom:event Emits SetTrustedRemoteAddress with remote chain Id and remote address\n */\n function setTrustedRemoteAddress(uint16 remoteChainId_, bytes calldata newRemoteAddress_) external {\n // _ensureAllowed(\"setTrustedRemoteAddress(uint16,bytes)\");\n require(remoteChainId_ != 0, \"OmnichainProposalSender: chainId must not be zero\");\n ensureNonzeroAddress(address(uint160(bytes20(newRemoteAddress_))));\n require(newRemoteAddress_.length == 20, \"OmnichainProposalSender: remote address must be 20 bytes long\");\n bytes memory oldRemoteAddress = trustedRemoteLookup[remoteChainId_];\n trustedRemoteLookup[remoteChainId_] = abi.encodePacked(newRemoteAddress_, address(this));\n emit SetTrustedRemoteAddress(remoteChainId_, oldRemoteAddress, trustedRemoteLookup[remoteChainId_]);\n }\n\n /**\n * @notice Sets the configuration of the LayerZero messaging library of the specified version\n * @param version_ Messaging library version\n * @param chainId_ The LayerZero chainId for the pending config change\n * @param configType_ The type of configuration. Every messaging library has its own convention\n * @param config_ The configuration in bytes. It can encode arbitrary content\n * @custom:access Controlled by AccessControlManager\n */\n function setConfig(uint16 version_, uint16 chainId_, uint256 configType_, bytes calldata config_) external {\n // _ensureAllowed(\"setConfig(uint16,uint16,uint256,bytes)\");\n LZ_ENDPOINT.setConfig(version_, chainId_, configType_, config_);\n }\n\n /**\n * @notice Sets the configuration of the LayerZero messaging library of the specified version\n * @param version_ New messaging library version\n * @custom:access Controlled by AccessControlManager\n */\n function setSendVersion(uint16 version_) external {\n // _ensureAllowed(\"setSendVersion(uint16)\");\n LZ_ENDPOINT.setSendVersion(version_);\n }\n\n /**\n * @notice Gets the configuration of the LayerZero messaging library of the specified version\n * @param version_ Messaging library version\n * @param chainId_ The LayerZero chainId\n * @param configType_ Type of configuration. Every messaging library has its own convention\n */\n function getConfig(uint16 version_, uint16 chainId_, uint256 configType_) external view returns (bytes memory) {\n return LZ_ENDPOINT.getConfig(version_, chainId_, address(this), configType_);\n }\n\n function _validateProposal(uint16 remoteChainId_, bytes memory payload_) internal {\n (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n\n ) = abi.decode(payload_, (address[], uint[], string[], bytes[], uint8));\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"OmnichainProposalSender: proposal function information arity mismatch\"\n );\n _isEligibleToSend(remoteChainId_, targets.length);\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" } }, "settings": { "optimizer": { "enabled": true, "runs": 10000 }, "evmVersion": "shanghai", "outputSelection": { "*": { "*": [ "storageLayout", "abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata", "devdoc", "userdoc", "evm.gasEstimates" ], "": ["ast"] } }, "metadata": { "useLiteralContent": true } } }