Skip to content

Commit c47199d

Browse files
authored
[eth] contract improvement (#348)
* Make Pyth.initialize private * Make contract upgrade more resillient + add fail test * Remove deployCommitHash The deployCommitHash process is error-prone and it's alternatives require changing many parts of the code. And as it is not used anywhere. I believe it is not worth the effort. * Improve price not found log
1 parent 62ef9d7 commit c47199d

File tree

5 files changed

+51
-24
lines changed

5 files changed

+51
-24
lines changed

ethereum/contracts/pyth/Pyth.sol

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ import "./PythInternalStructs.sol";
1414
abstract contract Pyth is PythGetters, PythSetters, AbstractPyth {
1515
using BytesLib for bytes;
1616

17-
function initialize(
17+
function _initialize(
1818
address wormhole,
1919
uint16 pyth2WormholeChainId,
2020
bytes32 pyth2WormholeEmitter
21-
) virtual public {
21+
) internal {
2222
setWormhole(wormhole);
2323
setPyth2WormholeChainId(pyth2WormholeChainId);
2424
setPyth2WormholeEmitter(pyth2WormholeEmitter);
@@ -222,7 +222,7 @@ abstract contract Pyth is PythGetters, PythSetters, AbstractPyth {
222222
function queryPriceFeed(bytes32 id) public view override returns (PythStructs.PriceFeed memory priceFeed){
223223
// Look up the latest price info for the given ID
224224
PythInternalStructs.PriceInfo memory info = latestPriceInfo(id);
225-
require(info.priceFeed.id != 0, "no price feed found for the given price id");
225+
require(info.priceFeed.id != 0, "price feed for the given id is not pushed or does not exist");
226226

227227
return info.priceFeed;
228228
}
@@ -236,17 +236,7 @@ abstract contract Pyth is PythGetters, PythSetters, AbstractPyth {
236236
return validTimePeriodSeconds();
237237
}
238238

239-
function isPyth() internal pure returns (bool) {
240-
return true;
241-
}
242-
243239
function version() public pure returns (string memory) {
244240
return "1.1.0";
245241
}
246-
247-
function deployCommitHash() public pure returns (string memory) {
248-
// This is a place holder for the commit hash and will be replaced
249-
// with the commit hash upon deployment.
250-
return "__DEPLOY_COMMIT_HASH_PLACEHOLER__";
251-
}
252242
}

ethereum/contracts/pyth/PythUpgradable.sol

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ contract PythUpgradable is Initializable, OwnableUpgradeable, UUPSUpgradeable, P
1818
address wormhole,
1919
uint16 pyth2WormholeChainId,
2020
bytes32 pyth2WormholeEmitter
21-
) initializer override public {
21+
) initializer public {
2222
__Ownable_init();
2323
__UUPSUpgradeable_init();
2424

25-
Pyth.initialize(wormhole, pyth2WormholeChainId, pyth2WormholeEmitter);
25+
Pyth._initialize(wormhole, pyth2WormholeChainId, pyth2WormholeEmitter);
2626
}
2727

2828
/// Privileged function to specify additional data sources in the contract
@@ -81,11 +81,18 @@ contract PythUpgradable is Initializable, OwnableUpgradeable, UUPSUpgradeable, P
8181
// Only allow the owner to upgrade the proxy to a new implementation.
8282
function _authorizeUpgrade(address) internal override onlyOwner {}
8383

84+
function pythUpgradableMagic() public pure returns (uint32) {
85+
return 0x97a6f304;
86+
}
87+
8488
// Execute a UpgradeContract governance message
8589
function upgradeUpgradableContract(UpgradeContractPayload memory payload) override internal {
8690
address oldImplementation = _getImplementation();
8791
_upgradeToAndCallUUPS(payload.newImplementation, new bytes(0), false);
88-
require(isPyth(), "the new implementation is not a Pyth contract");
92+
93+
// Calling a method using `this.<method>` will cause a contract call that will use
94+
// the new contract.
95+
require(this.pythUpgradableMagic() == 0x97a6f304, "the new implementation is not a Pyth contract");
8996

9097
emit ContractUpgraded(oldImplementation, _getImplementation());
9198
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// contracts/Implementation.sol
2+
// SPDX-License-Identifier: Apache 2
3+
4+
pragma solidity ^0.8.0;
5+
6+
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
7+
8+
contract MockUpgradeableProxy is UUPSUpgradeable {
9+
function isUpgradeActive() external pure returns (bool) {
10+
return true;
11+
}
12+
13+
function _authorizeUpgrade(address) internal override {}
14+
}

ethereum/deploy.sh

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ set -euo pipefail
1313

1414
echo "=========== Compiling ==========="
1515

16-
echo "Replacing the deploy commit hash..."
17-
# Set the deploy commit hash in the contract (used for debugging purposes)
18-
sed -i "s/__DEPLOY_COMMIT_HASH_PLACEHOLER__/$(git rev-parse HEAD)/g" ./contracts/pyth/Pyth.sol
19-
2016
echo "Building the contract..."
2117
# Ensure that we deploy a fresh build with up-to-date dependencies.
2218
rm -rf build && npx truffle compile --all
@@ -41,6 +37,4 @@ while [[ $# -ne 0 ]]; do
4137
echo "Deployment to $NETWORK finished successfully"
4238
done
4339

44-
echo "=========== Cleaning up ==========="
45-
echo "Reverting back the deploy commit hash..."
46-
sed -i "s/$(git rev-parse HEAD)/__DEPLOY_COMMIT_HASH_PLACEHOLER__/g" ./contracts/pyth/Pyth.sol
40+
echo "=========== Finished ==========="

ethereum/test/pyth.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const Wormhole = artifacts.require("Wormhole");
1515

1616
const PythUpgradable = artifacts.require("PythUpgradable");
1717
const MockPythUpgrade = artifacts.require("MockPythUpgrade");
18+
const MockUpgradeableProxy = artifacts.require("MockUpgradeableProxy");
1819

1920
const testSigner1PK =
2021
"cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0";
@@ -594,7 +595,7 @@ contract("Pyth", function () {
594595
this.pythProxy.queryPriceFeed(
595596
"0xdeadfeeddeadfeeddeadfeeddeadfeeddeadfeeddeadfeeddeadfeeddeadfeed"
596597
),
597-
"no price feed found for the given price id"
598+
"price feed for the given id is not pushed or does not exist"
598599
);
599600
});
600601

@@ -982,6 +983,27 @@ contract("Pyth", function () {
982983
});
983984
});
984985

986+
it("Upgrading the contract to a non-pyth contract won't work", async function () {
987+
const newImplementation = await MockUpgradeableProxy.new();
988+
989+
const data = new governance.EthereumUpgradeContractInstruction(
990+
governance.CHAINS.ethereum,
991+
new governance.HexString20Bytes(newImplementation.address),
992+
).serialize();
993+
994+
const vaa = await createVAAFromUint8Array(data,
995+
testGovernanceChainId,
996+
testGovernanceEmitter,
997+
1
998+
);
999+
1000+
// Calling a non-existing method will cause a revert with no explanation.
1001+
await expectRevert(
1002+
this.pythProxy.executeGovernanceInstruction(vaa),
1003+
"revert"
1004+
);
1005+
});
1006+
9851007
it("Setting governance data source should work", async function () {
9861008
const data = new governance.SetGovernanceDataSourceInstruction(
9871009
governance.CHAINS.ethereum,

0 commit comments

Comments
 (0)