Each network that Pyth is deployed on has some configuration stored on this repo in the contract manager package as described below:
id: id of the chain. This will be used for identifying which chain we want to deploy to.wormholeChainName: Chain name in Wormhole. It is either defined in the
Wormhole SDK constants
or is defined in Wormhole Receiver names. If the new
network requires a Receiver contract you need to update the latter file and add the network there.mainnet: A boolean which indicates whether the network is mainnet or testnet/devnet.rpcUrl: RPC endpoint of the network.networkId: id of the network. Used in RPC calls.address: The address the pyth contract is deployed on (this will refer to the proxy contract).chain: Name of the chain (id field in chain configuration) the contract is deployed on.If you wish to deploy to a new network you need to add the chain configurations as described above. You can find networkId and public
RPCs of most of the networks in ChainList. Rest of the parameters are optional and avoid
adding them unless it is necessary. Wormhole's
truffle-config.js
is a good reference too.
This is the deployment process:
migrations/prod to the Truffle development network first. You can do this by using the configuration
values in .env.prod.development.Pyth.sol and package.json.
Make sure to read the Upgrading the contract and Versioning
sections below.MNEMONIC environment variable like so: export MNEMONIC=$(cat path/to/mnemonic).Deploy the new contract or changes using the deploy.sh script.
You might need to repeat this script because of busy RPCs. Repeating would not cause any problem even
if the changes are already made. Also, sometimes the gases are not adjusted and it will cause the tx to
remain on the mempool for a long time (so there is no progress until timeout). Please update them with
the network explorer gas tracker. Tips in the Troubleshooting section below can help
in case of any error. Run the script like this: ./deploy.sh <network_a> <network_b> <...>. For example
to deploy changes to testnet networks you can run:
./deploy.sh bnb_testnet fantom_testnet mumbai
On first time deployments for a mainnet network with Wormhole Receiver contract, run this command:
npm run receiver-submit-guardian-sets -- --network <network>
As a result of this process for some files (with the network id in their name) in networks and directory might change
which need to be committed (if they are result of a production deployment). Create a PR for them.
If you are deploying to a new network, please add the new contract address to consumer facing libraries and documentations. The deployment script should automatically add the contract to the contract manager store. Please update the following resources:
(Optional) You can test the deployed contract by sending and fetching a price update as described in the Testing section below.
(Optional) Verify the contract as described in the Verifying the contract section.
networks directoryTruffle stores the address of the deployed contracts in the build artifacts, which can make local development difficult. We use truffle-deploy-registry to store the addresses separately from the artifacts, in the networks directory. When we need to perform operations on the deployed contracts, such as performing additional migrations, we can run npx apply-registry to populate the artifacts with the correct addresses.
Each file in the network directory is named after the network id and contains address of Migration contract and PythUpgradable contract
(and Wormhole Receiver if we use prod-receiver). If you are upgrading the contract it should not change. In case you are deploying to a new network make sure to commit this file.
To upgrade the contract you should bump the version of the contract and the npm package to the new version and run the deployment process described above. Please bump the version properly as described in the section below.
When you are making changes to the storage, please make sure that your change to the contract won't cause any collision. For example:
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.
If the Wormhole guardian set is going to change, you need to update the guardian set in the Wormhole receiver contracts. You should do it before the guardians start publishing VAAs with the new guardian set and not earlier than 24 hours before that to avoid any possible downtime. After updating the guardian set there is a 24 hour windows that the contracts will accept VAAs from both the old and the new index. So, you will need to do it when you are certain that Guardians will start publishing with the new set soon.
To update the guardian set update the
receiverSubmitGuardianSetUpgrades.js script and add the new VAA and comment out the previous upgrades.
Then, run it like below on the networks with Wormhole receiver contract:
npm run receiver-submit-guardian-sets -- --network <network>
You should create a PR to add this VAA to the repo for future deployments on new networks with Wormhole receiver contract.
We use Semantic Versioning 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 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.
The pyth-js repository contains an example with documentation and a code sample showing how to relay your own prices to a target Pyth network. Once you have relayed a price, you can verify the price feed has been updated by doing:
$ npx truffle console --network $MIGRATIONS_NETWORK
> let p = await PythUpgradable.deployed()
> p.queryPriceFeed("0xf9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b") // BTC Testnet or any other address
We include artifacts required for verifying the contract in each release. To create these artifacts, run the following commands:
npx sol-merger contracts/pyth/PythUpgradable.sol
npx sol-merger contracts/pyth/ReceiverImplementation.sol
npx truffle run stdjsonin PythUpgradable
npx truffle run stdjsonin ReceiverImplementation
These commands create the files contracts/pyth/PythUpgradable_merged.sol, contracts/pyth/ReceiverImplementation_merged.sol, PythUpgradable-input.json, and ReceiverImplementation-input.json respectively.
The .sol files are the flattened version of the contracts, and the .json files are the standard json input of the contracts.
Please include all of these in the release.
Read VERIFY.md for how to use these files to verify the contract.
digital envelope routines::unsupported error, it means you are using a new Node version and it does not work because
the truffle dependency is old. As a workaround, you can use the legacy openssl implementation by running this command:
export NODE_OPTIONS=--openssl-legacy-provider.Although zkSync is EVM compatible, their binary format is different than solc output. So, we need to use their libraries to compile it to their binary format (zk-solc) and deploy it. As of this writing they only support hardhat. To deploy a fresh contract or a new contract do the following steps in addition to the steps described above:
hardhad.config.ts file.npx hardhat clean && npx hardhat compile to have a clean compile the contracts.MNEMONIC environment variable like so: export MNEMONIC=$(cat path/to/mnemonic).node create-env.js zksync and verifying the .env file.npx hardhat deploy-zksync --network <network> --script deploy/zkSyncDeploy to deploy it to the new network. Otherwise
run npx hardhat deploy-zksync --network <network> --script deploy/zkSyncDeployNewPythImpl.ts to get a new implementation address. Then put it in
.<network>.new_impl file and run the deployment script to handle the rest of the changes.Canto network rewards some percentage of the gas usage to the contracts. To enable the rewards we have modified the contract upon deployment to register its own address as the receiver of the rewards and also assigned Pyth to received Wormhole Receiver rewards too. The registration only happens once for contract. The contracts are registered with token id 654. We don't need to register the contracts upon upgrades because the proxy address doesn't change. The contract changes for registration are stored in this diff for future reference. Please note that if we switch to another Wormhole Receiver (a new address) we will need to register the new contract.