PythGovernance.sol 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // contracts/Governance.sol
  2. // SPDX-License-Identifier: Apache 2
  3. pragma solidity ^0.8.0;
  4. import "./PythGovernanceInstructions.sol";
  5. import "./PythInternalStructs.sol";
  6. import "./PythGetters.sol";
  7. import "./PythSetters.sol";
  8. import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
  9. /**
  10. * @dev `Governance` defines a means to enacting changes to the Pyth contract.
  11. */
  12. abstract contract PythGovernance is
  13. PythGetters,
  14. PythSetters,
  15. PythGovernanceInstructions
  16. {
  17. event ContractUpgraded(
  18. address oldImplementation,
  19. address newImplementation
  20. );
  21. event GovernanceDataSourceSet(
  22. PythInternalStructs.DataSource oldDataSource,
  23. PythInternalStructs.DataSource newDataSource,
  24. uint64 initialSequence
  25. );
  26. event DataSourcesSet(
  27. PythInternalStructs.DataSource[] oldDataSources,
  28. PythInternalStructs.DataSource[] newDataSources
  29. );
  30. event FeeSet(uint oldFee, uint newFee);
  31. event ValidPeriodSet(uint oldValidPeriod, uint newValidPeriod);
  32. function verifyGovernanceVM(
  33. bytes memory encodedVM
  34. ) internal returns (IWormhole.VM memory parsedVM) {
  35. (IWormhole.VM memory vm, bool valid, string memory reason) = wormhole()
  36. .parseAndVerifyVM(encodedVM);
  37. require(valid, reason);
  38. require(
  39. isValidGovernanceDataSource(vm.emitterChainId, vm.emitterAddress),
  40. "VAA is not coming from the governance data source"
  41. );
  42. require(
  43. vm.sequence > lastExecutedGovernanceSequence(),
  44. "VAA is older than the last executed governance VAA"
  45. );
  46. setLastExecutedGovernanceSequence(vm.sequence);
  47. return vm;
  48. }
  49. function executeGovernanceInstruction(bytes calldata encodedVM) public {
  50. IWormhole.VM memory vm = verifyGovernanceVM(encodedVM);
  51. GovernanceInstruction memory gi = parseGovernanceInstruction(
  52. vm.payload
  53. );
  54. require(
  55. gi.targetChainId == chainId() || gi.targetChainId == 0,
  56. "invalid target chain for this governance instruction"
  57. );
  58. if (gi.action == GovernanceAction.UpgradeContract) {
  59. require(
  60. gi.targetChainId != 0,
  61. "upgrade with chain id 0 is not possible"
  62. );
  63. upgradeContract(parseUpgradeContractPayload(gi.payload));
  64. } else if (
  65. gi.action == GovernanceAction.AuthorizeGovernanceDataSourceTransfer
  66. ) {
  67. AuthorizeGovernanceDataSourceTransfer(
  68. parseAuthorizeGovernanceDataSourceTransferPayload(gi.payload)
  69. );
  70. } else if (gi.action == GovernanceAction.SetDataSources) {
  71. setDataSources(parseSetDataSourcesPayload(gi.payload));
  72. } else if (gi.action == GovernanceAction.SetFee) {
  73. setFee(parseSetFeePayload(gi.payload));
  74. } else if (gi.action == GovernanceAction.SetValidPeriod) {
  75. setValidPeriod(parseSetValidPeriodPayload(gi.payload));
  76. } else if (
  77. gi.action == GovernanceAction.RequestGovernanceDataSourceTransfer
  78. ) {
  79. revert(
  80. "RequestGovernanceDataSourceTransfer can be only part of AuthorizeGovernanceDataSourceTransfer message"
  81. );
  82. } else {
  83. revert("invalid governance action");
  84. }
  85. }
  86. function upgradeContract(UpgradeContractPayload memory payload) internal {
  87. // This method on this contract does not have enough access to execute this, it should be executed on the
  88. // upgradable contract.
  89. upgradeUpgradableContract(payload);
  90. }
  91. function upgradeUpgradableContract(
  92. UpgradeContractPayload memory payload
  93. ) internal virtual;
  94. // Transfer the governance data source to a new value with sanity checks
  95. // to ensure the new governance data source can manage the contract.
  96. function AuthorizeGovernanceDataSourceTransfer(
  97. AuthorizeGovernanceDataSourceTransferPayload memory payload
  98. ) internal {
  99. PythInternalStructs.DataSource
  100. memory oldGovernanceDatSource = governanceDataSource();
  101. // Make sure the claimVaa is a valid VAA with RequestGovernanceDataSourceTransfer governance message
  102. // If it's valid then its emitter can take over the governance from the current emitter.
  103. // The VAA is checked here to ensure that the new governance data source is valid and can send message
  104. // through wormhole.
  105. (IWormhole.VM memory vm, bool valid, string memory reason) = wormhole()
  106. .parseAndVerifyVM(payload.claimVaa);
  107. require(valid, reason);
  108. GovernanceInstruction memory gi = parseGovernanceInstruction(
  109. vm.payload
  110. );
  111. require(
  112. gi.targetChainId == chainId() || gi.targetChainId == 0,
  113. "invalid target chain for this governance instruction"
  114. );
  115. require(
  116. gi.action == GovernanceAction.RequestGovernanceDataSourceTransfer,
  117. "governance data source change inner vaa is not of claim action type"
  118. );
  119. RequestGovernanceDataSourceTransferPayload
  120. memory claimPayload = parseRequestGovernanceDataSourceTransferPayload(
  121. gi.payload
  122. );
  123. // Governance data source index is used to prevent replay attacks, so a claimVaa cannot be used twice.
  124. require(
  125. governanceDataSourceIndex() <
  126. claimPayload.governanceDataSourceIndex,
  127. "cannot upgrade to an older governance data source"
  128. );
  129. setGovernanceDataSourceIndex(claimPayload.governanceDataSourceIndex);
  130. PythInternalStructs.DataSource
  131. memory newGovernanceDS = PythInternalStructs.DataSource(
  132. vm.emitterChainId,
  133. vm.emitterAddress
  134. );
  135. setGovernanceDataSource(newGovernanceDS);
  136. // Setting the last executed governance to the claimVaa sequence to avoid using older sequences.
  137. setLastExecutedGovernanceSequence(vm.sequence);
  138. emit GovernanceDataSourceSet(
  139. oldGovernanceDatSource,
  140. governanceDataSource(),
  141. lastExecutedGovernanceSequence()
  142. );
  143. }
  144. function setDataSources(SetDataSourcesPayload memory payload) internal {
  145. PythInternalStructs.DataSource[]
  146. memory oldDataSources = validDataSources();
  147. for (uint i = 0; i < oldDataSources.length; i += 1) {
  148. _state.isValidDataSource[hashDataSource(oldDataSources[i])] = false;
  149. }
  150. delete _state.validDataSources;
  151. for (uint i = 0; i < payload.dataSources.length; i++) {
  152. _state.validDataSources.push(payload.dataSources[i]);
  153. _state.isValidDataSource[
  154. hashDataSource(payload.dataSources[i])
  155. ] = true;
  156. }
  157. emit DataSourcesSet(oldDataSources, validDataSources());
  158. }
  159. function setFee(SetFeePayload memory payload) internal {
  160. uint oldFee = singleUpdateFeeInWei();
  161. setSingleUpdateFeeInWei(payload.newFee);
  162. emit FeeSet(oldFee, singleUpdateFeeInWei());
  163. }
  164. function setValidPeriod(SetValidPeriodPayload memory payload) internal {
  165. uint oldValidPeriod = validTimePeriodSeconds();
  166. setValidTimePeriodSeconds(payload.newValidPeriod);
  167. emit ValidPeriodSet(oldValidPeriod, validTimePeriodSeconds());
  168. }
  169. }