Eth contract fix memory + new sdk + refactor (#257)
* Update sdk version * Update the contract according to the sdk changes - Change some memory modifiers to improve gas efficiency - Implement getValidTimePeriod() and remove old staleness logic - Update the tests * Update latest migration descriptions * Add version * Update Deploying.md * Add test to validate version of the contract * Add deploy commit hash * Rename the placeholder * Fix placeholder
This commit is contained in:
parent
995c886804
commit
a17b27f3d1
|
@ -18,6 +18,9 @@ rm -rf build && npx truffle compile --all
|
|||
# Merge the network addresses into the artifacts, if some contracts are already deployed.
|
||||
npx apply-registry
|
||||
|
||||
# Set the deploy commit hash in the contract binary (used for debugging purposes)
|
||||
sed -i "s/dead0beaf0deb10700c0331700da5d00deadbead/$(git rev-parse HEAD)/g" build/contracts/*
|
||||
|
||||
# Perform the migration
|
||||
npx truffle migrate --network $MIGRATIONS_NETWORK
|
||||
|
||||
|
@ -60,6 +63,8 @@ const PythUpgradable = artifacts.require("PythUpgradable");
|
|||
const { upgradeProxy } = require("@openzeppelin/truffle-upgrades");
|
||||
|
||||
/**
|
||||
* Version <x.y.z>.
|
||||
*
|
||||
* Briefly describe the changelog here.
|
||||
*/
|
||||
module.exports = async function (deployer) {
|
||||
|
@ -86,6 +91,12 @@ make sure that your change to the contract won't cause any collision**. For exam
|
|||
Anything other than the operations above will probably cause a collision. Please refer to Open Zeppelin Upgradeable
|
||||
(documentations)[https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable] for more information.
|
||||
|
||||
## Versioning
|
||||
|
||||
We use [Semantic Versioning](https://semver.org/) for our releases. When upgrading the contract, update the npm package version using
|
||||
`npm version <new version number> --no-git-tag-version`. Also, modify the hard-coded value in `version()` method in
|
||||
[the `Pyth.sol` contract](./contracts/pyth/Pyth.sol) to the new version. Then, after your PR is merged in main, create a release like with tag `pyth-evm-contract-v<x.y.z>`. This will help developers to be able to track code changes easier.
|
||||
|
||||
# Testing
|
||||
|
||||
The [pyth-js][] repository contains an example with documentation and a code sample showing how to relay your own prices to a
|
||||
|
|
|
@ -24,7 +24,7 @@ abstract contract Pyth is PythGetters, PythSetters, AbstractPyth {
|
|||
setPyth2WormholeEmitter(pyth2WormholeEmitter);
|
||||
}
|
||||
|
||||
function updatePriceBatchFromVm(bytes memory encodedVm) private returns (PythInternalStructs.BatchPriceAttestation memory bpa) {
|
||||
function updatePriceBatchFromVm(bytes calldata encodedVm) private returns (PythInternalStructs.BatchPriceAttestation memory bpa) {
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVm);
|
||||
|
||||
require(valid, reason);
|
||||
|
@ -211,34 +211,29 @@ abstract contract Pyth is PythGetters, PythSetters, AbstractPyth {
|
|||
}
|
||||
|
||||
function queryPriceFeed(bytes32 id) public view override returns (PythStructs.PriceFeed memory priceFeed){
|
||||
|
||||
// Look up the latest price info for the given ID
|
||||
PythInternalStructs.PriceInfo memory info = latestPriceInfo(id);
|
||||
require(info.priceFeed.id != 0, "no price feed found for the given price id");
|
||||
|
||||
// Check that there is not a significant difference between this chain's time
|
||||
// and the price publish time.
|
||||
if (info.priceFeed.status == PythStructs.PriceStatus.TRADING &&
|
||||
absDiff(block.timestamp, info.priceFeed.publishTime) > validTimePeriodSeconds()) {
|
||||
info.priceFeed.status = PythStructs.PriceStatus.UNKNOWN;
|
||||
// getLatestAvailablePrice* gets prevPrice when status is
|
||||
// unknown. So, now that status is being set to unknown,
|
||||
// we should move the current price to the previous
|
||||
// price to ensure getLatestAvailablePrice* works
|
||||
// as intended.
|
||||
info.priceFeed.prevPrice = info.priceFeed.price;
|
||||
info.priceFeed.prevConf = info.priceFeed.conf;
|
||||
info.priceFeed.prevPublishTime = info.priceFeed.publishTime;
|
||||
}
|
||||
|
||||
return info.priceFeed;
|
||||
}
|
||||
|
||||
function absDiff(uint x, uint y) private pure returns (uint) {
|
||||
if (x > y) {
|
||||
return x - y;
|
||||
} else {
|
||||
return y - x;
|
||||
}
|
||||
function priceFeedExists(bytes32 id) public override view returns (bool) {
|
||||
PythInternalStructs.PriceInfo memory info = latestPriceInfo(id);
|
||||
return (info.priceFeed.id != 0);
|
||||
}
|
||||
|
||||
function getValidTimePeriod() public override view returns (uint) {
|
||||
return validTimePeriodSeconds();
|
||||
}
|
||||
|
||||
function version() public pure returns (string memory) {
|
||||
return "0.1.0";
|
||||
}
|
||||
|
||||
function deployCommitHash() public pure returns (bytes20) {
|
||||
// This is a place holder for the commit hash and will be replaced
|
||||
// with the commit hash upon deployment.
|
||||
return hex"dead0beaf0deb10700c0331700da5d00deadbead";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,15 @@ const PythUpgradable = artifacts.require("PythUpgradable");
|
|||
const { upgradeProxy } = require("@openzeppelin/truffle-upgrades");
|
||||
|
||||
/**
|
||||
* Version 0.1.0
|
||||
*
|
||||
* This change:
|
||||
* - Updates the interface, adds `updatePriceFeedsIfNecessary` that wraps
|
||||
* `updatePriceFeeds` and rejects if the price update is not necessary.
|
||||
* - Changes some memory modifiers to improve gas efficiency.
|
||||
* - Changes staleness logic to be included in the sdk and bring
|
||||
* more clarity to the existing code.
|
||||
* - Adds version to the contract (which is hard coded)
|
||||
*/
|
||||
module.exports = async function (deployer) {
|
||||
const proxy = await PythUpgradable.deployed();
|
||||
|
|
|
@ -5,9 +5,15 @@ const PythUpgradable = artifacts.require("PythUpgradable");
|
|||
const { upgradeProxy } = require("@openzeppelin/truffle-upgrades");
|
||||
|
||||
/**
|
||||
* Version 0.1.0
|
||||
*
|
||||
* This change:
|
||||
* - Updates the interface, adds `updatePriceFeedsIfNecessary` that wraps
|
||||
* `updatePriceFeeds` and rejects if the price update is not necessary.
|
||||
* - Changes some memory modifiers to improve gas efficiency.
|
||||
* - Changes staleness logic to be included in the sdk and bring
|
||||
* more clarity to the existing code.
|
||||
* - Adds version to the contract (which is hard coded)
|
||||
*/
|
||||
module.exports = async function (deployer) {
|
||||
const proxy = await PythUpgradable.deployed();
|
||||
|
|
|
@ -5,9 +5,15 @@ const PythUpgradable = artifacts.require("PythUpgradable");
|
|||
const { upgradeProxy } = require("@openzeppelin/truffle-upgrades");
|
||||
|
||||
/**
|
||||
* Version 0.1.0
|
||||
*
|
||||
* This change:
|
||||
* - Updates the interface, adds `updatePriceFeedsIfNecessary` that wraps
|
||||
* `updatePriceFeeds` and rejects if the price update is not necessary.
|
||||
* - Changes some memory modifiers to improve gas efficiency.
|
||||
* - Changes staleness logic to be included in the sdk and bring
|
||||
* more clarity to the existing code.
|
||||
* - Adds version to the contract (which is hard coded)
|
||||
*/
|
||||
module.exports = async function (deployer) {
|
||||
const proxy = await PythUpgradable.deployed();
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
{
|
||||
"name": "wormhole",
|
||||
"version": "1.0.0",
|
||||
"name": "@pythnetwork/pyth-evm-contract",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wormhole",
|
||||
"version": "1.0.0",
|
||||
"name": "@pythnetwork/pyth-evm-contract",
|
||||
"version": "0.1.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^4.5.0",
|
||||
"@openzeppelin/contracts-upgradeable": "^4.5.2",
|
||||
"@pythnetwork/pyth-sdk-solidity": "^0.5.1",
|
||||
"@pythnetwork/pyth-sdk-solidity": "^0.5.2",
|
||||
"dotenv": "^10.0.0",
|
||||
"elliptic": "^6.5.2",
|
||||
"ganache-cli": "^6.12.1",
|
||||
|
@ -3674,9 +3674,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@pythnetwork/pyth-sdk-solidity": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-solidity/-/pyth-sdk-solidity-0.5.1.tgz",
|
||||
"integrity": "sha512-uvV48IPzkU4+q6PQZNbLnjT+xVaiLmnMEalMvLFK3+QRBpd8gTXm8izdO0ZPbKHdytOueTHxlFK5imo7hRabBA=="
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-solidity/-/pyth-sdk-solidity-0.5.2.tgz",
|
||||
"integrity": "sha512-On0hyZcTuMsonSzLc+HHA/5npjwB9WlFZlLrXW8TUV+7WEKH4o73OYJy/b9197E7snTviDIASlVT+rmcC9b7rg=="
|
||||
},
|
||||
"node_modules/@redux-saga/core": {
|
||||
"version": "1.1.3",
|
||||
|
@ -39998,9 +39998,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"@pythnetwork/pyth-sdk-solidity": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-solidity/-/pyth-sdk-solidity-0.5.1.tgz",
|
||||
"integrity": "sha512-uvV48IPzkU4+q6PQZNbLnjT+xVaiLmnMEalMvLFK3+QRBpd8gTXm8izdO0ZPbKHdytOueTHxlFK5imo7hRabBA=="
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/pyth-sdk-solidity/-/pyth-sdk-solidity-0.5.2.tgz",
|
||||
"integrity": "sha512-On0hyZcTuMsonSzLc+HHA/5npjwB9WlFZlLrXW8TUV+7WEKH4o73OYJy/b9197E7snTviDIASlVT+rmcC9b7rg=="
|
||||
},
|
||||
"@redux-saga/core": {
|
||||
"version": "1.1.3",
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
{
|
||||
"name": "wormhole",
|
||||
"version": "1.0.0",
|
||||
"name": "@pythnetwork/pyth-evm-contract",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"main": "networks.js",
|
||||
"devDependencies": {
|
||||
"@chainsafe/truffle-plugin-abigen": "0.0.1",
|
||||
"@openzeppelin/cli": "^2.8.2",
|
||||
|
@ -30,7 +29,7 @@
|
|||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^4.5.0",
|
||||
"@openzeppelin/contracts-upgradeable": "^4.5.2",
|
||||
"@pythnetwork/pyth-sdk-solidity": "^0.5.1",
|
||||
"@pythnetwork/pyth-sdk-solidity": "^0.5.2",
|
||||
"dotenv": "^10.0.0",
|
||||
"elliptic": "^6.5.2",
|
||||
"ganache-cli": "^6.12.1",
|
||||
|
|
|
@ -6,7 +6,7 @@ const PythStructs = artifacts.require("PythStructs");
|
|||
|
||||
const { deployProxy, upgradeProxy } = require("@openzeppelin/truffle-upgrades");
|
||||
const { expectRevert, expectEvent, time } = require("@openzeppelin/test-helpers");
|
||||
const { assert } = require("chai");
|
||||
const { assert, expect } = require("chai");
|
||||
|
||||
// Use "WormholeReceiver" if you are testing with Wormhole Receiver
|
||||
const Wormhole = artifacts.require("Wormhole");
|
||||
|
@ -562,7 +562,7 @@ contract("Pyth", function () {
|
|||
);
|
||||
});
|
||||
|
||||
it("should show stale cached prices as unknown", async function () {
|
||||
it("should revert on getting stale current prices", async function () {
|
||||
let smallestTimestamp = 1;
|
||||
let rawBatch = generateRawBatchAttestation(
|
||||
smallestTimestamp,
|
||||
|
@ -575,15 +575,14 @@ contract("Pyth", function () {
|
|||
const price_id =
|
||||
"0x" +
|
||||
(255 - (i % 256)).toString(16).padStart(2, "0").repeat(32);
|
||||
let priceFeedResult = await this.pythProxy.queryPriceFeed(price_id);
|
||||
assert.equal(
|
||||
priceFeedResult.status.toString(),
|
||||
PythStructs.PriceStatus.UNKNOWN.toString()
|
||||
expectRevert(
|
||||
this.pythProxy.getCurrentPrice(price_id),
|
||||
"current price unavailable"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("should show cached prices too far into the future as unknown", async function () {
|
||||
it("should revert on getting current prices too far into the future as they are considered unknown", async function () {
|
||||
let largestTimestamp = 4294967295;
|
||||
let rawBatch = generateRawBatchAttestation(
|
||||
largestTimestamp - 5,
|
||||
|
@ -596,10 +595,9 @@ contract("Pyth", function () {
|
|||
const price_id =
|
||||
"0x" +
|
||||
(255 - (i % 256)).toString(16).padStart(2, "0").repeat(32);
|
||||
let priceFeedResult = await this.pythProxy.queryPriceFeed(price_id);
|
||||
assert.equal(
|
||||
priceFeedResult.status.toString(),
|
||||
PythStructs.PriceStatus.UNKNOWN.toString()
|
||||
expectRevert(
|
||||
this.pythProxy.getCurrentPrice(price_id),
|
||||
"current price unavailable"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -622,11 +620,9 @@ contract("Pyth", function () {
|
|||
const price_id =
|
||||
"0x" +
|
||||
(255 - (i % 256)).toString(16).padStart(2, "0").repeat(32);
|
||||
let priceFeedResult = await this.pythProxy.queryPriceFeed(price_id);
|
||||
assert.equal(
|
||||
priceFeedResult.status.toString(),
|
||||
PythStructs.PriceStatus.TRADING.toString()
|
||||
);
|
||||
|
||||
// Expect getCurrentPrice to work (not revert)
|
||||
await this.pythProxy.getCurrentPrice(price_id);
|
||||
}
|
||||
|
||||
// One minute passes
|
||||
|
@ -637,10 +633,10 @@ contract("Pyth", function () {
|
|||
const price_id =
|
||||
"0x" +
|
||||
(255 - (i % 256)).toString(16).padStart(2, "0").repeat(32);
|
||||
let priceFeedResult = await this.pythProxy.queryPriceFeed(price_id);
|
||||
assert.equal(
|
||||
priceFeedResult.status.toString(),
|
||||
PythStructs.PriceStatus.UNKNOWN.toString()
|
||||
|
||||
expectRevert(
|
||||
this.pythProxy.getCurrentPrice(price_id),
|
||||
"current price unavailable"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -653,10 +649,9 @@ contract("Pyth", function () {
|
|||
"0x" +
|
||||
(255 - (i % 256)).toString(16).padStart(2, "0").repeat(32);
|
||||
let priceFeedResult = await this.pythProxy.queryPriceFeed(price_id);
|
||||
assert.equal(
|
||||
priceFeedResult.status.toString(),
|
||||
PythStructs.PriceStatus.TRADING.toString()
|
||||
);
|
||||
|
||||
// Expect getCurrentPrice to work (not revert)
|
||||
await this.pythProxy.getCurrentPrice(price_id);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -724,6 +719,13 @@ contract("Pyth", function () {
|
|||
"invalid data source chain/emitter ID"
|
||||
);
|
||||
});
|
||||
|
||||
it("Make sure version is the npm package version", async function () {
|
||||
const contractVersion = await this.pythProxy.version();
|
||||
const { version } = require('../package.json');
|
||||
|
||||
expect(contractVersion).equal(version);
|
||||
});
|
||||
});
|
||||
|
||||
const signAndEncodeVM = async function (
|
||||
|
|
Loading…
Reference in New Issue