PythGovernanceInstructions.sol 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // contracts/GovernanceStructs.sol
  2. // SPDX-License-Identifier: Apache 2
  3. pragma solidity ^0.8.0;
  4. import "../libraries/external/BytesLib.sol";
  5. import "./PythInternalStructs.sol";
  6. /**
  7. * @dev `PythGovernanceInstructions` defines a set of structs and parsing functions
  8. * for Pyth governance instructions.
  9. */
  10. contract PythGovernanceInstructions {
  11. using BytesLib for bytes;
  12. // Magic is `PTGM` encoded as a 4 byte data: Pyth Governance Message
  13. uint32 constant MAGIC = 0x5054474d;
  14. enum GovernanceModule {
  15. Executor, // 0
  16. Target // 1
  17. }
  18. GovernanceModule constant MODULE = GovernanceModule.Target;
  19. enum GovernanceAction {
  20. UpgradeContract, // 0
  21. AuthorizeGovernanceDataSourceTransfer, // 1
  22. SetDataSources, // 2
  23. SetFee, // 3
  24. SetValidPeriod, // 4
  25. RequestGovernanceDataSourceTransfer // 5
  26. }
  27. struct GovernanceInstruction {
  28. GovernanceModule module;
  29. GovernanceAction action;
  30. uint16 targetChainId;
  31. bytes payload;
  32. }
  33. struct UpgradeContractPayload {
  34. address newImplementation;
  35. }
  36. struct AuthorizeGovernanceDataSourceTransferPayload {
  37. // Transfer governance control over this contract to another data source.
  38. // The claimVaa field is a VAA created by the new data source; using a VAA prevents mistakes
  39. // in the handoff by ensuring that the new data source can send VAAs (i.e., is not an invalid address).
  40. bytes claimVaa;
  41. }
  42. struct RequestGovernanceDataSourceTransferPayload {
  43. // Governance data source index is used to prevent replay attacks
  44. // So a claimVaa cannot be used twice.
  45. uint32 governanceDataSourceIndex;
  46. }
  47. struct SetDataSourcesPayload {
  48. PythInternalStructs.DataSource[] dataSources;
  49. }
  50. struct SetFeePayload {
  51. uint newFee;
  52. }
  53. struct SetValidPeriodPayload {
  54. uint newValidPeriod;
  55. }
  56. /// @dev Parse a GovernanceInstruction
  57. function parseGovernanceInstruction(
  58. bytes memory encodedInstruction
  59. ) public pure returns (GovernanceInstruction memory gi) {
  60. uint index = 0;
  61. uint32 magic = encodedInstruction.toUint32(index);
  62. require(magic == MAGIC, "invalid magic for GovernanceInstruction");
  63. index += 4;
  64. uint8 modNumber = encodedInstruction.toUint8(index);
  65. gi.module = GovernanceModule(modNumber);
  66. index += 1;
  67. require(
  68. gi.module == MODULE,
  69. "invalid module for GovernanceInstruction"
  70. );
  71. uint8 actionNumber = encodedInstruction.toUint8(index);
  72. gi.action = GovernanceAction(actionNumber);
  73. index += 1;
  74. gi.targetChainId = encodedInstruction.toUint16(index);
  75. index += 2;
  76. // As solidity performs math operations in a checked mode
  77. // if the length of the encoded instruction be smaller than index
  78. // it will revert. So we don't need any extra check.
  79. gi.payload = encodedInstruction.slice(
  80. index,
  81. encodedInstruction.length - index
  82. );
  83. }
  84. /// @dev Parse a UpgradeContractPayload (action 1) with minimal validation
  85. function parseUpgradeContractPayload(
  86. bytes memory encodedPayload
  87. ) public pure returns (UpgradeContractPayload memory uc) {
  88. uint index = 0;
  89. uc.newImplementation = address(encodedPayload.toAddress(index));
  90. index += 20;
  91. require(
  92. encodedPayload.length == index,
  93. "invalid length for UpgradeContractPayload"
  94. );
  95. }
  96. /// @dev Parse a AuthorizeGovernanceDataSourceTransferPayload (action 2) with minimal validation
  97. function parseAuthorizeGovernanceDataSourceTransferPayload(
  98. bytes memory encodedPayload
  99. )
  100. public
  101. pure
  102. returns (AuthorizeGovernanceDataSourceTransferPayload memory sgds)
  103. {
  104. sgds.claimVaa = encodedPayload;
  105. }
  106. /// @dev Parse a AuthorizeGovernanceDataSourceTransferPayload (action 2) with minimal validation
  107. function parseRequestGovernanceDataSourceTransferPayload(
  108. bytes memory encodedPayload
  109. )
  110. public
  111. pure
  112. returns (RequestGovernanceDataSourceTransferPayload memory sgdsClaim)
  113. {
  114. uint index = 0;
  115. sgdsClaim.governanceDataSourceIndex = encodedPayload.toUint32(index);
  116. index += 4;
  117. require(
  118. encodedPayload.length == index,
  119. "invalid length for RequestGovernanceDataSourceTransferPayload"
  120. );
  121. }
  122. /// @dev Parse a SetDataSourcesPayload (action 3) with minimal validation
  123. function parseSetDataSourcesPayload(
  124. bytes memory encodedPayload
  125. ) public pure returns (SetDataSourcesPayload memory sds) {
  126. uint index = 0;
  127. uint8 dataSourcesLength = encodedPayload.toUint8(index);
  128. index += 1;
  129. sds.dataSources = new PythInternalStructs.DataSource[](
  130. dataSourcesLength
  131. );
  132. for (uint i = 0; i < dataSourcesLength; i++) {
  133. sds.dataSources[i].chainId = encodedPayload.toUint16(index);
  134. index += 2;
  135. sds.dataSources[i].emitterAddress = encodedPayload.toBytes32(index);
  136. index += 32;
  137. }
  138. require(
  139. encodedPayload.length == index,
  140. "invalid length for SetDataSourcesPayload"
  141. );
  142. }
  143. /// @dev Parse a SetFeePayload (action 4) with minimal validation
  144. function parseSetFeePayload(
  145. bytes memory encodedPayload
  146. ) public pure returns (SetFeePayload memory sf) {
  147. uint index = 0;
  148. uint64 val = encodedPayload.toUint64(index);
  149. index += 8;
  150. uint64 expo = encodedPayload.toUint64(index);
  151. index += 8;
  152. sf.newFee = uint256(val) * uint256(10) ** uint256(expo);
  153. require(
  154. encodedPayload.length == index,
  155. "invalid length for SetFeePayload"
  156. );
  157. }
  158. /// @dev Parse a SetValidPeriodPayload (action 5) with minimal validation
  159. function parseSetValidPeriodPayload(
  160. bytes memory encodedPayload
  161. ) public pure returns (SetValidPeriodPayload memory svp) {
  162. uint index = 0;
  163. svp.newValidPeriod = uint256(encodedPayload.toUint64(index));
  164. index += 8;
  165. require(
  166. encodedPayload.length == index,
  167. "invalid length for SetValidPeriodPayload"
  168. );
  169. }
  170. }