Skip to content

Commit 5320c58

Browse files
authored
Implement the new IPyth events and methods (#241)
* Implement the new IPyth events and methods * Check contracts gets the fees in tests * Fix the fee variable position to avoid conflict * Add migration files. * Add events to migration names and docs * Fix pyth contract address in tests Very strangely after adding migration steps the old address used in evm relay became wormhole implementation address I looked at eth-0/tests container logs and saw the address is entirely different (before and after the change) * Fix previous migration bug. * rename instance to proxy to be more clear * Update Deploying.md
1 parent 07bf9db commit 5320c58

17 files changed

+302
-36
lines changed

devnet/p2w-evm-relay.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ spec:
6464
- name: EVM_HDWALLET_PATH
6565
value: "m/44'/60'/0'/0/1" # Use account with idx 1
6666
- name: EVM_PYTH_CONTRACT_ADDRESS
67-
value: "0xDb56f2e9369E0D7bD191099125a3f6C370F8ed15"
67+
value: "0xe982E462b094850F12AF94d21D470e21bE9D0E9C"
6868
- name: EVM_VERIFY_PRICE_FEEDS
6969
value: "yes"
7070
- name: REST_PORT

devnet/pyth-evm-watcher.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ spec:
2424
- name: WS_ENDPOINT
2525
value: 'ws://eth-devnet:8545'
2626
- name: PYTH_CONTRACT
27-
value: '0xDb56f2e9369E0D7bD191099125a3f6C370F8ed15'
27+
value: '0xe982E462b094850F12AF94d21D470e21bE9D0E9C'

ethereum/Deploying.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ for more information.
4848
Changes to the files in this directory should be commited as well.
4949

5050
# Upgrading the contract
51-
To upgrade the contract you should add a new migration file in the `migrations/prod` directory increasing the migration number.
51+
To upgrade the contract you should add a new migration file in the `migrations/*` directories increasing the migration number.
5252

5353
It looks like so:
5454

@@ -63,8 +63,8 @@ const { upgradeProxy } = require("@openzeppelin/truffle-upgrades");
6363
* Briefly describe the changelog here.
6464
*/
6565
module.exports = async function (deployer) {
66-
const instance = await PythUpgradable.deployed();
67-
await upgradeProxy(instance.address, PythUpgradable, { deployer });
66+
const proxy = await PythUpgradable.deployed();
67+
await upgradeProxy(proxy.address, PythUpgradable, { deployer });
6868
}
6969
```
7070

ethereum/contracts/pyth/Pyth.sol

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,51 @@ abstract contract Pyth is PythGetters, PythSetters, AbstractPyth {
2424
setPyth2WormholeEmitter(pyth2WormholeEmitter);
2525
}
2626

27-
function updatePriceBatchFromVm(bytes memory encodedVm) public returns (PythInternalStructs.BatchPriceAttestation memory bpa) {
27+
function updatePriceBatchFromVm(bytes memory encodedVm) private returns (PythInternalStructs.BatchPriceAttestation memory bpa) {
2828
(IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(encodedVm);
2929

3030
require(valid, reason);
3131
require(verifyPythVM(vm), "invalid data source chain/emitter ID");
3232

3333
PythInternalStructs.BatchPriceAttestation memory batch = parseBatchPriceAttestation(vm.payload);
3434

35+
uint freshPrices = 0;
36+
3537
for (uint i = 0; i < batch.attestations.length; i++) {
3638
PythInternalStructs.PriceAttestation memory attestation = batch.attestations[i];
3739

3840
PythInternalStructs.PriceInfo memory latestPrice = latestPriceInfo(attestation.priceId);
3941

42+
bool fresh = false;
4043
if(attestation.attestationTime > latestPrice.attestationTime) {
44+
freshPrices += 1;
45+
fresh = true;
4146
setLatestPriceInfo(attestation.priceId, newPriceInfo(attestation));
42-
emit PriceUpdate(attestation.priceId, attestation.publishTime);
4347
}
48+
49+
emit PriceFeedUpdate(attestation.priceId, fresh, vm.emitterChainId, vm.sequence, latestPrice.priceFeed.publishTime,
50+
attestation.publishTime, attestation.price, attestation.conf);
4451
}
4552

53+
emit BatchPriceFeedUpdate(vm.emitterChainId, vm.sequence, batch.attestations.length, freshPrices);
54+
4655
return batch;
4756
}
4857

49-
function updatePriceFeeds(bytes[] calldata updateData) public override {
58+
function updatePriceFeeds(bytes[] calldata updateData) public override payable {
59+
uint requiredFee = getUpdateFee(updateData.length);
60+
require(msg.value >= requiredFee, "Insufficient paid fee amount");
61+
payable(msg.sender).transfer(msg.value - requiredFee);
62+
5063
for(uint i = 0; i < updateData.length; i++) {
5164
updatePriceBatchFromVm(updateData[i]);
5265
}
66+
67+
emit UpdatePriceFeeds(msg.sender, updateData.length, requiredFee);
68+
}
69+
70+
function getUpdateFee(uint updateDataSize) public override view returns (uint feeAmount) {
71+
return singleUpdateFeeInWei() * updateDataSize;
5372
}
5473

5574
function newPriceInfo(PythInternalStructs.PriceAttestation memory pa) private view returns (PythInternalStructs.PriceInfo memory info) {

ethereum/contracts/pyth/PythGetters.sol

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,9 @@ contract PythGetters is PythState {
3434
function validDataSources() public view returns (PythInternalStructs.DataSource[] memory) {
3535
return _state.validDataSources;
3636
}
37+
38+
39+
function singleUpdateFeeInWei() public view returns (uint) {
40+
return _state.singleUpdateFeeInWei;
41+
}
3742
}

ethereum/contracts/pyth/PythSetters.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@ contract PythSetters is PythState {
2121
function setLatestPriceInfo(bytes32 priceId, PythInternalStructs.PriceInfo memory info) internal {
2222
_state.latestPriceInfo[priceId] = info;
2323
}
24+
25+
function setSingleUpdateFeeInWei(uint fee) internal {
26+
_state.singleUpdateFeeInWei = fee;
27+
}
2428
}

ethereum/contracts/pyth/PythState.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ contract PythStorage {
2121
// (chainId, emitterAddress) => isValid; takes advantage of
2222
// constant-time mapping lookup for VM verification
2323
mapping(bytes32 => bool) isValidDataSource;
24+
25+
uint singleUpdateFeeInWei;
2426
}
2527
}
2628

ethereum/contracts/pyth/PythUpgradable.sol

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ contract PythUpgradable is Initializable, OwnableUpgradeable, UUPSUpgradeable, P
5555
}
5656
}
5757

58+
/// Privileged function to update the price update fee
59+
function updateSingleUpdateFeeInWei(uint newFee) onlyOwner public {
60+
PythSetters.setSingleUpdateFeeInWei(newFee);
61+
}
62+
5863
/// Ensures the contract cannot be uninitialized and taken over.
5964
/// @custom:oz-upgrades-unsafe-allow constructor
6065
constructor() initializer {}

ethereum/migrations/prod-receiver/4_pyth_multiple_emitters.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ const { upgradeProxy } = require("@openzeppelin/truffle-upgrades");
88
* Adds multiple emitter/chain ID support
99
*/
1010
module.exports = async function (deployer) {
11-
const instance = await PythUpgradable.deployed();
12-
await instance.addDataSource(
13-
instance.pyth2WormholeChainId(),
14-
instance.pyth2WormholeEmitter()
11+
const proxy = await PythUpgradable.deployed();
12+
await upgradeProxy(proxy.address, PythUpgradable, { deployer });
13+
await proxy.addDataSource(
14+
proxy.pyth2WormholeChainId(),
15+
proxy.pyth2WormholeEmitter()
1516
);
1617
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
require('dotenv').config({ path: "../.env" });
2+
3+
const PythUpgradable = artifacts.require("PythUpgradable");
4+
5+
const { upgradeProxy } = require("@openzeppelin/truffle-upgrades");
6+
7+
/**
8+
* This change:
9+
* - Adds fee for updating prices. Default value in Ethereum is 0, so the value after upgrade will be 0.
10+
* - Emits multiple events when a price gets updated. This can be used by off-chain applications to monitor
11+
* the contract activity.
12+
*/
13+
module.exports = async function (deployer) {
14+
const proxy = await PythUpgradable.deployed();
15+
await upgradeProxy(proxy.address, PythUpgradable, { deployer });
16+
}

0 commit comments

Comments
 (0)