|
| 1 | +# Pyth EVM price pusher |
| 2 | + |
| 3 | +Pyth EVM price pusher is a service that regularly pushes updates to the on-chain Pyth price based on configurable conditions. |
| 4 | + |
| 5 | +## Background |
| 6 | + |
| 7 | +Pyth is a cross-chain oracle that streams price updates over the peer-to-peer [Wormhole Network](https://wormholenetwork.com/). |
| 8 | +These price updates can be consumed on any chain that has a deployment of the Pyth contract. |
| 9 | +By default, Pyth does not automatically update the on-chain price every time the off-chain price changes; |
| 10 | +instead, anyone can permissionlessly update the on-chain price prior to using it. |
| 11 | +For more information please refer to [this document](../pyth-evm-js/README.md#how-pyth-works-on-evm-chains). |
| 12 | + |
| 13 | +Protocols integrating with can update the on-chain Pyth prices in two different ways. |
| 14 | +The first approach is on-demand updates: package a Pyth price update together with each transaction that depends on it. |
| 15 | +On-demand updates minimize latency and are more gas efficient, as prices are only updated on-chain when they are needed. |
| 16 | + |
| 17 | +The second approach is to run this service to regularly push updates to the on-chain price. |
| 18 | +This approach is useful for protocols that already depend on regular push updates. |
| 19 | + |
| 20 | +## Running Price Pusher |
| 21 | + |
| 22 | +The price pusher service monitors both the off-chain and on-chain Pyth price for a configured set of price feeds. |
| 23 | +It then pushes a price update to an on-chain Pyth contract if any of the following conditions are met: |
| 24 | + |
| 25 | +- Time difference: The on-chain price is older than `time_difference` seconds |
| 26 | + from the latest Pyth price. |
| 27 | +- Price deviation: The latest Pyth price feed has changed more than `price_deviation` percent |
| 28 | + from the on-chain price feed price. |
| 29 | +- Confidence ratio: The latest Pyth price feed has confidence to price ratio of more than |
| 30 | + `confidence_ratio`. |
| 31 | + |
| 32 | +The parameters above are configured per price feed in a price configuration YAML file. The structure looks like this: |
| 33 | + |
| 34 | +```yaml |
| 35 | +- alias: A/USD # Arbitrary alias for the price feed. It is used in enhance logging. |
| 36 | + id: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef # id of a price feed, a 32-byte hex string. |
| 37 | + time_difference: 60 # Time difference threshold (in seconds) to push a newer price feed. |
| 38 | + price_deviation: 0.5 # The price deviation (%) threshold to push a newer price feed. |
| 39 | + confidence_ratio: 1 # The confidence/price (%) threshold to push a newer price feed. |
| 40 | +- ... |
| 41 | +``` |
| 42 | +
|
| 43 | +You can get the list of available price feeds from |
| 44 | +[here](https://pyth.network/developers/price-feed-ids/). |
| 45 | +
|
| 46 | +To run the price pusher, please run the following commands, replacing the command line arguments as necessary: |
| 47 | +
|
| 48 | +```sh |
| 49 | +npm install # Only run it the first time |
| 50 | + |
| 51 | +npm run start -- --evm-endpoint wss://example-rpc.com --mnemonic-file "path/to/mnemonic.txt" \ |
| 52 | + --pyth-contract example_network --price-endpoint https://example-pyth-price.com \ |
| 53 | + --price-config-file "path/to/price-config-file.yaml" \ |
| 54 | + [--cooldown-duration 10] \ |
| 55 | + [--evm-polling-frequency 5] |
| 56 | + |
| 57 | +# Or, run the price pusher docker image instead of building from the source |
| 58 | +docker run public.ecr.aws/pyth-network/xc-evm-price-pusher:v<version> -- <above-arguments> |
| 59 | +``` |
| 60 | + |
| 61 | +### Command Line Arguments |
| 62 | + |
| 63 | +The program accepts the following command line arguments: |
| 64 | + |
| 65 | +- `evm-endpoint`: RPC endpoint URL for the EVM network. If you provide a normal HTTP endpoint, |
| 66 | + the pusher will periodically poll for updates. The polling interval is configurable via the |
| 67 | + `evm-polling-frequency` command-line argument (described below). If you provide a websocket RPC endpoint |
| 68 | + (`ws[s]://...`), the price pusher will use event subscriptions to read the current EVM |
| 69 | + price in addition to polling. |
| 70 | +- `mnemonic-file`: Path to payer mnemonic (private key) file. |
| 71 | +- `pyth-contract`: The Pyth contract address. Provide the network name on which Pyth is deployed |
| 72 | + or the Pyth contract address if you use a local network. |
| 73 | + You can find the networks on which pyth is live and their corresponding names |
| 74 | + [here](../pyth-evm-js/src/index.ts#L13). An example is `bnb_testnet`. |
| 75 | +- `price-endpoint`: Endpoint URL for the price service. You can use |
| 76 | + `https://xc-testnet.pyth.network` for testnet and |
| 77 | + `https://xc-mainnet.pyth.network` for mainnet. It is recommended |
| 78 | + to run a standalone price service for more resiliency. |
| 79 | +- `price-config-file`: Path to price configuration YAML file. |
| 80 | +- `cooldown-duration` (Optional): The amount of time (in seconds) to wait between pushing |
| 81 | + price updates. It should be greater than the block time of the network, so this |
| 82 | + program confirms the price is updated and does not push it twice. Default: 10 seconds. |
| 83 | +- `evm-polling-frequency` (Optional): The frequency to poll price info data from the EVM network |
| 84 | + if the RPC is not a Websocket. It has no effect if the RPC is a Websocket. |
| 85 | + Default: 5 seconds. |
| 86 | + |
| 87 | +### Example |
| 88 | + |
| 89 | +For example, to push `BTC/USD` and `BNB/USD` prices on BNB testnet, run the following command: |
| 90 | + |
| 91 | +```sh |
| 92 | +npm run start -- --evm-endpoint "https://data-seed-prebsc-1-s1.binance.org:8545" --mnemonic-file "path/to/mnemonic.txt" \ |
| 93 | + --pyth-contract bnb_testnet --price-endpoint https://xc-testnet.pyth.network \ |
| 94 | + --price-config-file "price-config.testnet.sample.yaml" |
| 95 | +``` |
| 96 | + |
| 97 | +[`price-config.testnet.sample.yaml`](./price-config.testnet.sample.yaml) contains configuration for `BTC/USD` |
| 98 | +and `BNB/USD` price feeds on Pyth testnet. [`price-config.mainnet.sample.yaml`](./price-config.mainnet.sample.yaml) |
| 99 | +contains the same configuration for `BTC/USD` and `BNB/USD` on Pyth mainnet. |
| 100 | + |
| 101 | +## Running using a standalone price service (via docker-compose) |
| 102 | + |
| 103 | +EVM price pusher communicates with [Pyth price service][] to get the most recent price updates. Pyth price service listens to the |
| 104 | +Wormhole network to get latest price updates, and serves REST and websocket APIs for consumers to fetch the updates. |
| 105 | +Pyth hosts public endpoints for the price service; however, it is recommended to run it standalone to achieve more resiliency and |
| 106 | +scalability. |
| 107 | + |
| 108 | +This directory contains sample docker compose files ([testnet](./docker-compose.testnet.sample.yaml), |
| 109 | +[mainnet](./docker-compose.mainnet.sample.yaml)) an EVM price pusher and its dependencies, including a |
| 110 | +price service and a Wormhole spy. A price service depends on a Wormhole spy. A spy listens to the Wormhole |
| 111 | +network and reports all Pyth-related Wormhole messages to the price service. |
| 112 | + |
| 113 | +To run the services via docker-compose, please modify the your target network (testnet, mainnet) sample docker-compose file to adjust |
| 114 | +the path to your mnemonic file, the path to your price configuration file, the EVM endpoint, and the Pyth contract address |
| 115 | +as necessary. |
| 116 | + |
| 117 | +Then, start the docker-compose like this: |
| 118 | + |
| 119 | +``` |
| 120 | +docker-compose -f docker-compose.testnet.sample.yaml up |
| 121 | +``` |
| 122 | + |
| 123 | +It will take a few minutes until all the services are up and running. |
| 124 | + |
| 125 | +[pyth price service]: https://github.com/pyth-network/pyth-crosschain/tree/main/third_party/pyth/price-service |
0 commit comments