wormhole/ethereum/contracts/pyth/PythGovernance.sol

90 lines
3.0 KiB
Solidity

// contracts/Bridge.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
import "../libraries/external/BytesLib.sol";
import "./PythGetters.sol";
import "./PythSetters.sol";
import "./PythStructs.sol";
import "../interfaces/IWormhole.sol";
contract PythGovernance is PythGetters, PythSetters, ERC1967Upgrade {
using BytesLib for bytes;
bytes32 constant module = 0x0000000000000000000000000000000000000000000000000000000050797468;
// Execute a UpgradeContract governance message
function upgrade(bytes memory encodedVM) public {
(IWormhole.VM memory vm, bool valid, string memory reason) = verifyGovernanceVM(encodedVM);
require(valid, reason);
setGovernanceActionConsumed(vm.hash);
PythStructs.UpgradeContract memory implementation = parseContractUpgrade(vm.payload);
require(implementation.module == module, "wrong module");
require(implementation.chain == chainId(), "wrong chain id");
upgradeImplementation(implementation.newContract);
}
function verifyGovernanceVM(bytes memory encodedVM) internal view returns (IWormhole.VM memory parsedVM, bool isValid, string memory invalidReason){
(IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVM);
if(!valid){
return (vm, valid, reason);
}
if (vm.emitterChainId != governanceChainId()) {
return (vm, false, "wrong governance chain");
}
if (vm.emitterAddress != governanceContract()) {
return (vm, false, "wrong governance contract");
}
if(governanceActionIsConsumed(vm.hash)){
return (vm, false, "governance action already consumed");
}
return (vm, true, "");
}
event ContractUpgraded(address indexed oldContract, address indexed newContract);
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);
}
function parseContractUpgrade(bytes memory encodedUpgrade) public pure returns (PythStructs.UpgradeContract memory cu) {
uint index = 0;
cu.module = encodedUpgrade.toBytes32(index);
index += 32;
cu.action = encodedUpgrade.toUint8(index);
index += 1;
require(cu.action == 1, "invalid ContractUpgrade 1");
cu.chain = encodedUpgrade.toUint16(index);
index += 2;
cu.newContract = address(uint160(uint256(encodedUpgrade.toBytes32(index))));
index += 32;
require(encodedUpgrade.length == index, "invalid ContractUpgrade 2");
}
}