PythGovernance.sol 7.1 KB

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