// contracts/Governance.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "./Structs.sol"; import "./GovernanceStructs.sol"; import "./Messages.sol"; import "./Setters.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol"; /** * @dev `Governance` defines a means to enacting changes to the core bridge contract, * guardianSets, message fees, and transfer fees */ abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upgrade { event ContractUpgraded(address indexed oldContract, address indexed newContract); event GuardianSetAdded(uint32 indexed index); // "Core" (left padded) bytes32 constant module = 0x00000000000000000000000000000000000000000000000000000000436f7265; /** * @dev Upgrades a contract via Governance VAA/VM */ function submitContractUpgrade(bytes memory _vm) public { Structs.VM memory vm = parseVM(_vm); // Verify the VAA is valid before processing it (bool isValid, string memory reason) = verifyGovernanceVM(vm); require(isValid, reason); GovernanceStructs.ContractUpgrade memory upgrade = parseContractUpgrade(vm.payload); // Verify the VAA is for this module require(upgrade.module == module, "Invalid Module"); // Verify the VAA is for this chain require(upgrade.chain == chainId(), "Invalid Chain"); // Record the governance action as consumed setGovernanceActionConsumed(vm.hash); // Upgrades the implementation to the new contract upgradeImplementation(upgrade.newContract); } /** * @dev Sets a `messageFee` via Governance VAA/VM */ function submitSetMessageFee(bytes memory _vm) public { Structs.VM memory vm = parseVM(_vm); // Verify the VAA is valid before processing it (bool isValid, string memory reason) = verifyGovernanceVM(vm); require(isValid, reason); GovernanceStructs.SetMessageFee memory upgrade = parseSetMessageFee(vm.payload); // Verify the VAA is for this module require(upgrade.module == module, "Invalid Module"); // Verify the VAA is for this chain require(upgrade.chain == chainId(), "Invalid Chain"); // Record the governance action as consumed to prevent reentry setGovernanceActionConsumed(vm.hash); // Updates the messageFee setMessageFee(upgrade.messageFee); } /** * @dev Deploys a new `guardianSet` via Governance VAA/VM */ function submitNewGuardianSet(bytes memory _vm) public { Structs.VM memory vm = parseVM(_vm); // Verify the VAA is valid before processing it (bool isValid, string memory reason) = verifyGovernanceVM(vm); require(isValid, reason); GovernanceStructs.GuardianSetUpgrade memory upgrade = parseGuardianSetUpgrade(vm.payload); // Verify the VAA is for this module require(upgrade.module == module, "invalid Module"); // Verify the VAA is for this chain require(upgrade.chain == chainId() || upgrade.chain == 0, "invalid Chain"); // Verify the Guardian Set keys are not empty, this guards // against the accidential upgrade to an empty GuardianSet require(upgrade.newGuardianSet.keys.length > 0, "new guardian set is empty"); // Verify that the index is incrementing via a predictable +1 pattern require(upgrade.newGuardianSetIndex == getCurrentGuardianSetIndex() + 1, "index must increase in steps of 1"); // Record the governance action as consumed to prevent reentry setGovernanceActionConsumed(vm.hash); // Trigger a time-based expiry of current guardianSet expireGuardianSet(getCurrentGuardianSetIndex()); // Add the new guardianSet to guardianSets storeGuardianSet(upgrade.newGuardianSet, upgrade.newGuardianSetIndex); // Makes the new guardianSet effective updateGuardianSetIndex(upgrade.newGuardianSetIndex); } /** * @dev Submits transfer fees to the recipient via Governance VAA/VM */ function submitTransferFees(bytes memory _vm) public { Structs.VM memory vm = parseVM(_vm); // Verify the VAA is valid before processing it (bool isValid, string memory reason) = verifyGovernanceVM(vm); require(isValid, reason); // Obtains the transfer from the VAA payload GovernanceStructs.TransferFees memory transfer = parseTransferFees(vm.payload); // Verify the VAA is for this module require(transfer.module == module, "invalid Module"); // Verify the VAA is for this chain require(transfer.chain == chainId() || transfer.chain == 0, "invalid Chain"); // Record the governance action as consumed to prevent reentry setGovernanceActionConsumed(vm.hash); // Obtains the recipient address to be paid transfer fees address payable recipient = payable(address(uint160(uint256(transfer.recipient)))); // Transfers transfer fees to the recipient recipient.transfer(transfer.amount); } /** * @dev Upgrades the `currentImplementation` with a `newImplementation` */ function upgradeImplementation(address newImplementation) internal { address currentImplementation = _getImplementation(); _upgradeTo(newImplementation); // Call initialize function of the new implementation (bool success, bytes memory reason) = newImplementation.delegatecall(abi.encodeWithSignature("initialize()")); require(success, string(reason)); emit ContractUpgraded(currentImplementation, newImplementation); } /** * @dev Verifies a Governance VAA/VM is valid */ function verifyGovernanceVM(Structs.VM memory vm) internal view returns (bool, string memory){ // Verify the VAA is valid (bool isValid, string memory reason) = verifyVM(vm); if (!isValid){ return (false, reason); } // only current guardianset can sign governance packets if (vm.guardianSetIndex != getCurrentGuardianSetIndex()) { return (false, "not signed by current guardian set"); } // Verify the VAA is from the governance chain (Solana) if (uint16(vm.emitterChainId) != governanceChainId()) { return (false, "wrong governance chain"); } // Verify the emitter contract is the governance contract (0x4 left padded) if (vm.emitterAddress != governanceContract()) { return (false, "wrong governance contract"); } // Verify this governance action hasn't already been // consumed to prevent reentry and replay if (governanceActionIsConsumed(vm.hash)){ return (false, "governance action already consumed"); } // Confirm the governance VAA/VM is valid return (true, ""); } }