PythUpgradable.sol 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // SPDX-License-Identifier: Apache 2
  2. pragma solidity ^0.8.0;
  3. import "./Pyth.sol";
  4. import "./PythInternalStructs.sol";
  5. import "./PythGetters.sol";
  6. import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
  7. import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
  8. import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
  9. import "./PythGovernance.sol";
  10. import "./Pyth.sol";
  11. contract PythUpgradable is
  12. Initializable,
  13. OwnableUpgradeable,
  14. UUPSUpgradeable,
  15. Pyth,
  16. PythGovernance
  17. {
  18. function initialize(
  19. address wormhole,
  20. uint16 pyth2WormholeChainId,
  21. bytes32 pyth2WormholeEmitter
  22. ) public initializer {
  23. __Ownable_init();
  24. __UUPSUpgradeable_init();
  25. Pyth._initialize(wormhole, pyth2WormholeChainId, pyth2WormholeEmitter);
  26. }
  27. /// Privileged function to specify additional data sources in the contract
  28. function addDataSource(uint16 chainId, bytes32 emitter) public onlyOwner {
  29. PythInternalStructs.DataSource memory ds = PythInternalStructs
  30. .DataSource(chainId, emitter);
  31. require(
  32. !PythGetters.isValidDataSource(ds.chainId, ds.emitterAddress),
  33. "Data source already added"
  34. );
  35. _state.isValidDataSource[hashDataSource(ds)] = true;
  36. _state.validDataSources.push(ds);
  37. }
  38. /// Privileged fucntion to remove the specified data source. Assumes _state.validDataSources has no duplicates.
  39. function removeDataSource(
  40. uint16 chainId,
  41. bytes32 emitter
  42. ) public onlyOwner {
  43. PythInternalStructs.DataSource memory ds = PythInternalStructs
  44. .DataSource(chainId, emitter);
  45. require(
  46. PythGetters.isValidDataSource(ds.chainId, ds.emitterAddress),
  47. "Data source not found, not removing"
  48. );
  49. _state.isValidDataSource[hashDataSource(ds)] = false;
  50. for (uint i = 0; i < _state.validDataSources.length; ++i) {
  51. // Find the source to remove
  52. if (
  53. _state.validDataSources[i].chainId == ds.chainId ||
  54. _state.validDataSources[i].emitterAddress == ds.emitterAddress
  55. ) {
  56. // Copy last element to overwrite the target data source
  57. _state.validDataSources[i] = _state.validDataSources[
  58. _state.validDataSources.length - 1
  59. ];
  60. // Remove the last element we just preserved
  61. _state.validDataSources.pop();
  62. break;
  63. }
  64. }
  65. }
  66. /// Privileged function to update the price update fee
  67. function updateSingleUpdateFeeInWei(uint newFee) public onlyOwner {
  68. PythSetters.setSingleUpdateFeeInWei(newFee);
  69. }
  70. /// Privileged function to update the valid time period for a price.
  71. function updateValidTimePeriodSeconds(
  72. uint newValidTimePeriodSeconds
  73. ) public onlyOwner {
  74. PythSetters.setValidTimePeriodSeconds(newValidTimePeriodSeconds);
  75. }
  76. // Privileged function to update the governance emitter
  77. function updateGovernanceDataSource(
  78. uint16 chainId,
  79. bytes32 emitter,
  80. uint64 sequence
  81. ) public onlyOwner {
  82. PythInternalStructs.DataSource memory ds = PythInternalStructs
  83. .DataSource(chainId, emitter);
  84. PythSetters.setGovernanceDataSource(ds);
  85. PythSetters.setLastExecutedGovernanceSequence(sequence);
  86. }
  87. /// Ensures the contract cannot be uninitialized and taken over.
  88. /// @custom:oz-upgrades-unsafe-allow constructor
  89. constructor() initializer {}
  90. // Only allow the owner to upgrade the proxy to a new implementation.
  91. function _authorizeUpgrade(address) internal override onlyOwner {}
  92. function pythUpgradableMagic() public pure returns (uint32) {
  93. return 0x97a6f304;
  94. }
  95. // Execute a UpgradeContract governance message
  96. function upgradeUpgradableContract(
  97. UpgradeContractPayload memory payload
  98. ) internal override {
  99. address oldImplementation = _getImplementation();
  100. _upgradeToAndCallUUPS(payload.newImplementation, new bytes(0), false);
  101. // Calling a method using `this.<method>` will cause a contract call that will use
  102. // the new contract.
  103. require(
  104. this.pythUpgradableMagic() == 0x97a6f304,
  105. "the new implementation is not a Pyth contract"
  106. );
  107. emit ContractUpgraded(oldImplementation, _getImplementation());
  108. }
  109. }