pyth-crosschain/ethereum/contracts/pyth/PythUpgradable.sol

138 lines
4.8 KiB
Solidity

// 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.<method>` 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());
}
}