// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; import "./Pyth.sol"; import "./PythInternalStructs.sol"; import "./PythGetters.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "./PythGovernance.sol"; import "./Pyth.sol"; import "@pythnetwork/pyth-sdk-solidity/PythErrors.sol"; contract PythUpgradable is Initializable, OwnableUpgradeable, UUPSUpgradeable, Pyth, PythGovernance { function initialize( address wormhole, uint16[] calldata dataSourceEmitterChainIds, bytes32[] calldata dataSourceEmitterAddresses, uint validTimePeriodSeconds, uint singleUpdateFeeInWei ) public initializer { __Ownable_init(); __UUPSUpgradeable_init(); Pyth._initialize( wormhole, dataSourceEmitterChainIds, dataSourceEmitterAddresses, validTimePeriodSeconds, singleUpdateFeeInWei ); } /// Privileged function to specify additional data sources in the contract function addDataSource(uint16 chainId, bytes32 emitter) public onlyOwner { PythInternalStructs.DataSource memory ds = PythInternalStructs .DataSource(chainId, emitter); require( !PythGetters.isValidDataSource(ds.chainId, ds.emitterAddress), "Data source already added" ); _state.isValidDataSource[hashDataSource(ds)] = true; _state.validDataSources.push(ds); } /// Privileged fucntion to remove the specified data source. Assumes _state.validDataSources has no duplicates. function removeDataSource( uint16 chainId, bytes32 emitter ) public onlyOwner { PythInternalStructs.DataSource memory ds = PythInternalStructs .DataSource(chainId, emitter); require( PythGetters.isValidDataSource(ds.chainId, ds.emitterAddress), "Data source not found, not removing" ); _state.isValidDataSource[hashDataSource(ds)] = false; for (uint i = 0; i < _state.validDataSources.length; ++i) { // Find the source to remove if ( _state.validDataSources[i].chainId == ds.chainId || _state.validDataSources[i].emitterAddress == ds.emitterAddress ) { // Copy last element to overwrite the target data source _state.validDataSources[i] = _state.validDataSources[ _state.validDataSources.length - 1 ]; // Remove the last element we just preserved _state.validDataSources.pop(); break; } } } /// Privileged function to update the price update fee function updateSingleUpdateFeeInWei(uint newFee) public onlyOwner { PythSetters.setSingleUpdateFeeInWei(newFee); } /// Privileged function to update the valid time period for a price. function updateValidTimePeriodSeconds( uint newValidTimePeriodSeconds ) public onlyOwner { PythSetters.setValidTimePeriodSeconds(newValidTimePeriodSeconds); } // Privileged function to update the governance emitter function updateGovernanceDataSource( uint16 chainId, bytes32 emitter, uint64 sequence ) public onlyOwner { PythInternalStructs.DataSource memory ds = PythInternalStructs .DataSource(chainId, emitter); PythSetters.setGovernanceDataSource(ds); PythSetters.setLastExecutedGovernanceSequence(sequence); } /// Ensures the contract cannot be uninitialized and taken over. /// @custom:oz-upgrades-unsafe-allow constructor constructor() initializer {} // Only allow the owner to upgrade the proxy to a new implementation. function _authorizeUpgrade(address) internal override onlyOwner {} function pythUpgradableMagic() public pure returns (uint32) { return 0x97a6f304; } // Execute a UpgradeContract governance message function upgradeUpgradableContract( UpgradeContractPayload memory payload ) internal override { address oldImplementation = _getImplementation(); _upgradeToAndCallUUPS(payload.newImplementation, new bytes(0), false); // Calling a method using `this.` will cause a contract call that will use // the new contract. This call will fail if the method does not exists or the magic // is different. if (this.pythUpgradableMagic() != 0x97a6f304) revert PythErrors.InvalidGovernanceMessage(); emit ContractUpgraded(oldImplementation, _getImplementation()); } }