pyth-crosschain/ethereum/contracts/pyth/PythGovernance.sol

117 lines
4.8 KiB
Solidity

// contracts/Governance.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./PythGovernanceInstructions.sol";
import "./PythInternalStructs.sol";
import "./PythGetters.sol";
import "./PythSetters.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
/**
* @dev `Governance` defines a means to enacting changes to the Pyth contract.
*/
abstract contract PythGovernance is PythGetters, PythSetters, PythGovernanceInstructions {
event ContractUpgraded(address oldImplementation, address newImplementation);
event GovernanceDataSourceSet(PythInternalStructs.DataSource oldDataSource, PythInternalStructs.DataSource newDataSource,
uint64 initialSequence);
event DataSourcesSet(PythInternalStructs.DataSource[] oldDataSources, PythInternalStructs.DataSource[] newDataSources);
event FeeSet(uint oldFee, uint newFee);
event ValidPeriodSet(uint oldValidPeriod, uint newValidPeriod);
function verifyGovernanceVM(bytes memory encodedVM) internal returns (IWormhole.VM memory parsedVM){
(IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVM);
require(valid, reason);
require(isValidGovernanceDataSource(vm.emitterChainId, vm.emitterAddress), "VAA is not coming from the governance data source");
require(vm.sequence > lastExecutedGovernanceSequence(), "VAA is older than the last executed governance VAA");
setLastExecutedGovernanceSequence(vm.sequence);
return vm;
}
function executeGovernanceInstruction(bytes calldata encodedVM) public {
IWormhole.VM memory vm = verifyGovernanceVM(encodedVM);
GovernanceInstruction memory gi = parseGovernanceInstruction(vm.payload);
require(gi.targetChainId == chainId() || gi.targetChainId == 0, "invalid target chain for this governance instruction");
if (gi.action == GovernanceAction.UpgradeContract) {
require(gi.targetChainId != 0, "upgrade with chain id 0 is not possible");
upgradeContract(gi.payload);
} else if (gi.action == GovernanceAction.SetGovernanceDataSource) {
setGovernanceDataSource(gi.payload);
} else if (gi.action == GovernanceAction.SetDataSources) {
setDataSources(gi.payload);
} else if (gi.action == GovernanceAction.SetFee) {
setFee(gi.payload);
} else if (gi.action == GovernanceAction.SetValidPeriod) {
setValidPeriod(gi.payload);
} else {
revert("invalid governance action");
}
}
function upgradeContract(bytes memory encodedPayload) internal {
UpgradeContractPayload memory payload = parseUpgradeContractPayload(encodedPayload);
// This contract does not have enough access to execute this, it should be executed on the
// upgradable
upgradeUpgradableContract(payload);
}
function upgradeUpgradableContract(UpgradeContractPayload memory payload) virtual internal;
function setGovernanceDataSource(bytes memory encodedPayload) internal {
SetGovernanceDataSourcePayload memory payload = parseSetGovernanceDataSourcePayload(encodedPayload);
PythInternalStructs.DataSource memory oldGovernanceDatSource = governanceDataSource();
setGovernanceDataSource(payload.newGovernanceDataSource);
setLastExecutedGovernanceSequence(payload.initialSequence);
emit GovernanceDataSourceSet(oldGovernanceDatSource, governanceDataSource(), lastExecutedGovernanceSequence());
}
function setDataSources(bytes memory encodedPayload) internal {
SetDataSourcesPayload memory payload = parseSetDataSourcesPayload(encodedPayload);
PythInternalStructs.DataSource[] memory oldDataSources = validDataSources();
for (uint i = 0; i < oldDataSources.length; i += 1) {
_state.isValidDataSource[hashDataSource(oldDataSources[i])] = false;
}
delete _state.validDataSources;
for (uint i = 0; i < payload.dataSources.length; i++) {
_state.validDataSources.push(payload.dataSources[i]);
_state.isValidDataSource[hashDataSource(payload.dataSources[i])] = true;
}
emit DataSourcesSet(oldDataSources, validDataSources());
}
function setFee(bytes memory encodedPayload) internal {
SetFeePayload memory payload = parseSetFeePayload(encodedPayload);
uint oldFee = singleUpdateFeeInWei();
setSingleUpdateFeeInWei(payload.newFee);
emit FeeSet(oldFee, singleUpdateFeeInWei());
}
function setValidPeriod(bytes memory encodedPayload) internal {
SetValidPeriodPayload memory payload = parseSetValidPeriodPayload(encodedPayload);
uint oldValidPeriod = validTimePeriodSeconds();
setValidTimePeriodSeconds(payload.newValidPeriod);
emit ValidPeriodSet(oldValidPeriod, validTimePeriodSeconds());
}
}