diff --git a/README.md b/README.md index d2d6eb4515..7688507404 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Within this monorepo you will find the following subprojects: This directory contains on-chain contracts and SDKs for all of the various blockchain runtimes that Pyth supports. Each subdirectory corresponds to a blockchain runtime. Inside each subdirectory, there are subfolders for -contracts, SDKs, and examples. +contracts and SDKs. ## Hermes @@ -27,7 +27,7 @@ The [`price_service/client`](./price_service/client/) directory provides an SDK However, most users will interact with the price service via a chain-specific SDK For a guide on utilising this service in your project, see the chain-specific SDK -and examples for your blockchain runtime in the `target_chains` directory. +and [examples](https://github.com/pyth-network/pyth-examples/tree/main/price_feeds) for your blockchain runtime in the `target_chains` directory. ## Fortuna diff --git a/target_chains/ethereum/examples/coin_flip/README.md b/target_chains/ethereum/examples/coin_flip/README.md deleted file mode 100644 index f772b452ef..0000000000 --- a/target_chains/ethereum/examples/coin_flip/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Coin Flip Example application - -The coin flip example demonstrates how to use Pyth Entropy to flip a fair coin. - -## Try it out - -To try the example, first run the following commands from the root of the `pyth-crosschain` repository: - -```shell -pnpm i -pnpm exec lerna run build -``` - -These commands will build dependencies for the typescript project. - -Next, choose a network to run the example on. -The example has been deployed on the following networks: - -``` -| Chain Name | Address | RPC | -|------------------|--------------------------------------------|--------------------------------------------| -| optimism-sepolia | 0x2eE67fF5d8548fF544f2c178a0FcAFe503A634Be | https://sepolia.optimism.io/ | -| arbitrum-sepolia | 0xCd76c50c3210C5AaA9c39D53A4f95BFd8b1a3a19 | https://sepolia-rollup.arbitrum.io/rpc | -``` - -You will also need the private key of a wallet with some gas tokens for your chosen network. -Then, from the `coin_flip/app` directory, run the following command: - -``` -npm run flip-coin -- \ - --private-key \ - --address
\ - --rpc-url -``` - -You can populate the arguments to this command from the table above. -The command should print output like this: - -```text -Running coin flip prototcol. -1. Generating user's random number... - number : 0x7c94c33d424e0a683deb15b55cc7d40d5cc8154478c76c971b677c35e32cb2f4 -2. Requesting coin flip... - fee : 101 wei - tx : 0x23e8e1c800d2e9c55d7e8bf1b2bd5e835979c1aa076f56ab4a74828a45684d9b - sequence : 37 -3. Waiting for result... - result : Tails -``` - -## Understanding the Example - -The example consists of a Solidity contract and a Typescript script. -See the extensive code comments in the contract at `contract/src/CoinFlip.sol` to learn how the example works. -The typescript script is available at `app/src/flip_coin.ts` and demonstrates how to interact with the contract. diff --git a/target_chains/ethereum/examples/coin_flip/app/.gitignore b/target_chains/ethereum/examples/coin_flip/app/.gitignore deleted file mode 100644 index 86cfbb24c7..0000000000 --- a/target_chains/ethereum/examples/coin_flip/app/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -lib -.dccache -*mnemonic* diff --git a/target_chains/ethereum/examples/coin_flip/app/package.json b/target_chains/ethereum/examples/coin_flip/app/package.json deleted file mode 100644 index 38eef823af..0000000000 --- a/target_chains/ethereum/examples/coin_flip/app/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "@pythnetwork/eth-coin-flip-example", - "version": "0.1.0", - "private": true, - "dependencies": { - "@pythnetwork/pyth-evm-js": "workspace:*", - "@pythnetwork/pyth-sdk-solidity": "workspace:*", - "@truffle/hdwallet-provider": "^2.1.15", - "@types/jest": "^27.5.2", - "@types/node": "^16.11.64", - "buffer": "^6.0.3", - "ethers": "^5.7.2", - "prettier": "^2.7.1", - "typescript": "^4.8.4", - "web3": "^1.8.1", - "yargs": "^17.7.2" - }, - "devDependencies": { - "@types/yargs": "^17.0.32", - "ts-node": "^10.9.1" - }, - "scripts": { - "build": "tsc", - "flip-coin": "pnpm run build && node lib/flip_coin.js", - "format": "prettier --write src/" - } -} diff --git a/target_chains/ethereum/examples/coin_flip/app/src/CoinFlipAbi.json b/target_chains/ethereum/examples/coin_flip/app/src/CoinFlipAbi.json deleted file mode 100644 index 1959c2e5a0..0000000000 --- a/target_chains/ethereum/examples/coin_flip/app/src/CoinFlipAbi.json +++ /dev/null @@ -1,81 +0,0 @@ -[ - { - "type": "constructor", - "inputs": [ - { "name": "_entropy", "type": "address", "internalType": "address" }, - { - "name": "_entropyProvider", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "nonpayable" - }, - { "type": "receive", "stateMutability": "payable" }, - { - "type": "function", - "name": "_entropyCallback", - "inputs": [ - { "name": "sequence", "type": "uint64", "internalType": "uint64" }, - { "name": "provider", "type": "address", "internalType": "address" }, - { "name": "randomNumber", "type": "bytes32", "internalType": "bytes32" } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "getFlipFee", - "inputs": [], - "outputs": [ - { "name": "fee", "type": "uint256", "internalType": "uint256" } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "requestFlip", - "inputs": [ - { - "name": "userRandomNumber", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [], - "stateMutability": "payable" - }, - { - "type": "event", - "name": "FlipRequest", - "inputs": [ - { - "name": "sequenceNumber", - "type": "uint64", - "indexed": false, - "internalType": "uint64" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "FlipResult", - "inputs": [ - { - "name": "sequenceNumber", - "type": "uint64", - "indexed": false, - "internalType": "uint64" - }, - { - "name": "isHeads", - "type": "bool", - "indexed": false, - "internalType": "bool" - } - ], - "anonymous": false - }, - { "type": "error", "name": "InsufficientFee", "inputs": [] } -] diff --git a/target_chains/ethereum/examples/coin_flip/app/src/flip_coin.ts b/target_chains/ethereum/examples/coin_flip/app/src/flip_coin.ts deleted file mode 100644 index d0acc3a59f..0000000000 --- a/target_chains/ethereum/examples/coin_flip/app/src/flip_coin.ts +++ /dev/null @@ -1,103 +0,0 @@ -import Web3 from "web3"; -import yargs from "yargs"; -import { hideBin } from "yargs/helpers"; -import HDWalletProvider from "@truffle/hdwallet-provider"; -import CoinFlipAbi from "./CoinFlipAbi.json"; - -const parser = yargs(hideBin(process.argv)) - .option("private-key", { - description: "Private key (as a hexadecimal string) of the sender", - type: "string", - required: true, - }) - .option("address", { - description: "The address of the CoinFlip contract", - type: "string", - required: true, - }) - .option("rpc-url", { - description: - "The URL of an ETH RPC service for reading/writing to the blockchain", - type: "string", - required: true, - }) - .help() - .alias("help", "h") - .parserConfiguration({ - "parse-numbers": false, - }); - -async function main() { - const argv = await parser.argv; - - const coinFlipContractAddress = argv.address; - const rpc = argv.rpcUrl; - const privateKey = argv.privateKey; - - const provider = new HDWalletProvider({ - privateKeys: [privateKey], - providerOrUrl: rpc, - }); - - const web3 = new Web3(provider as any); - - const coinFlipContract = new web3.eth.Contract( - CoinFlipAbi as any, - coinFlipContractAddress - ); - - console.log(`Running coin flip prototcol.`); - - console.log("1. Generating user's random number..."); - const randomNumber = web3.utils.randomHex(32); - console.log(` number : ${randomNumber}`); - - console.log("2. Requesting coin flip..."); - const flipFee = await coinFlipContract.methods.getFlipFee().call(); - console.log(` fee : ${flipFee} wei`); - - const receipt = await coinFlipContract.methods - .requestFlip(randomNumber) - .send({ value: flipFee, from: provider.getAddress(0) }); - - console.log(` tx : ${receipt.transactionHash}`); - const sequenceNumber = receipt.events.FlipRequest.returnValues.sequenceNumber; - console.log(` sequence : ${sequenceNumber}`); - - console.log("3. Waiting for result..."); - // Poll for new FlipResult events emitted by the CoinFlip contract. It checks if the event - // has the same sequenceNumber as the request. If it does, - // it logs the result and stops polling. - let fromBlock = receipt.blockNumber; - const intervalId = setInterval(async () => { - const currentBlock = await web3.eth.getBlockNumber(); - - if (fromBlock > currentBlock) { - return; - } - - // Get 'FlipResult' events emitted by the CoinFlip contract for given block range. - const events = await coinFlipContract.getPastEvents("FlipResult", { - fromBlock: fromBlock, - toBlock: currentBlock, - }); - fromBlock = currentBlock + 1; - - // Find the event with the same sequence number as the request. - const event = events.find( - (event) => event.returnValues.sequenceNumber === sequenceNumber - ); - - // If the event is found, log the result and stop polling. - if (event !== undefined) { - console.log( - ` result : ${event.returnValues.isHeads ? "Heads" : "Tails"}` - ); - clearInterval(intervalId); - } - }, 1000); - - provider.engine.stop(); -} - -main(); diff --git a/target_chains/ethereum/examples/coin_flip/app/tsconfig.json b/target_chains/ethereum/examples/coin_flip/app/tsconfig.json deleted file mode 100644 index 14becd49dc..0000000000 --- a/target_chains/ethereum/examples/coin_flip/app/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../../../../tsconfig.base.json", - "compilerOptions": { - "target": "esnext", - "module": "commonjs", - "declaration": true, - "rootDir": "src/", - "outDir": "./lib", - "strict": true, - "esModuleInterop": true, - "resolveJsonModule": true - }, - "include": ["src", "src/*.json"], - "exclude": ["node_modules"] -} diff --git a/target_chains/ethereum/examples/coin_flip/contract/.gitignore b/target_chains/ethereum/examples/coin_flip/contract/.gitignore deleted file mode 100644 index e9f63b3418..0000000000 --- a/target_chains/ethereum/examples/coin_flip/contract/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -lib/* -!lib/README.md -cache -out diff --git a/target_chains/ethereum/examples/coin_flip/contract/foundry.toml b/target_chains/ethereum/examples/coin_flip/contract/foundry.toml deleted file mode 100644 index db25c7154b..0000000000 --- a/target_chains/ethereum/examples/coin_flip/contract/foundry.toml +++ /dev/null @@ -1,7 +0,0 @@ -[profile.default] -solc = '0.8.4' -src = 'src' -out = 'out' -libs = ['lib', '../../../entropy_sdk/solidity'] - -# See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/target_chains/ethereum/examples/coin_flip/contract/lib/README.md b/target_chains/ethereum/examples/coin_flip/contract/lib/README.md deleted file mode 100644 index 41b1cdfa62..0000000000 --- a/target_chains/ethereum/examples/coin_flip/contract/lib/README.md +++ /dev/null @@ -1 +0,0 @@ -Forge installs the dependencies in this folder. They are .gitignored diff --git a/target_chains/ethereum/examples/coin_flip/contract/remappings.txt b/target_chains/ethereum/examples/coin_flip/contract/remappings.txt deleted file mode 100644 index cb63f8ee44..0000000000 --- a/target_chains/ethereum/examples/coin_flip/contract/remappings.txt +++ /dev/null @@ -1,3 +0,0 @@ -ds-test/=lib/forge-std/lib/ds-test/src/ -forge-std/=lib/forge-std/src/ -entropy-sdk-solidity/=../../../entropy_sdk/solidity/ diff --git a/target_chains/ethereum/examples/coin_flip/contract/scripts/deploy.sh b/target_chains/ethereum/examples/coin_flip/contract/scripts/deploy.sh deleted file mode 100755 index ea03f508ef..0000000000 --- a/target_chains/ethereum/examples/coin_flip/contract/scripts/deploy.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -e - -# URL of the ethereum RPC node to use. Choose this based on your target network -RPC_URL=https://sepolia-rollup.arbitrum.io/rpc - -# The address of the Pyth contract on your network. See the list of contract addresses here https://docs.pyth.network/documentation/pythnet-price-feeds/evm -ENTROPY_CONTRACT_ADDRESS="0x549Ebba8036Ab746611B4fFA1423eb0A4Df61440" -PROVIDER="0x6CC14824Ea2918f5De5C2f75A9Da968ad4BD6344" - -# Deployments -# optimism-sepolia 0x2eE67fF5d8548fF544f2c178a0FcAFe503A634Be -# arbitrum-sepolia 0xCd76c50c3210C5AaA9c39D53A4f95BFd8b1a3a19 - -# Note the -l here uses a ledger wallet to deploy your contract. You may need to change this -# option if you are using a different wallet. -forge create src/CoinFlip.sol:CoinFlip \ - -l \ - --rpc-url $RPC_URL \ - --constructor-args \ - $ENTROPY_CONTRACT_ADDRESS \ - $PROVIDER diff --git a/target_chains/ethereum/examples/coin_flip/contract/src/CoinFlip.sol b/target_chains/ethereum/examples/coin_flip/contract/src/CoinFlip.sol deleted file mode 100644 index bdf646a4d2..0000000000 --- a/target_chains/ethereum/examples/coin_flip/contract/src/CoinFlip.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: Apache 2 -pragma solidity ^0.8.0; - -// Import the entropy SDK in order to interact with the entropy contracts -import "entropy-sdk-solidity/IEntropy.sol"; -import "entropy-sdk-solidity/IEntropyConsumer.sol"; - -library CoinFlipErrors { - error InsufficientFee(); -} - -/// Example contract using Pyth Entropy to allow a user to flip a secure fair coin. -/// Users interact with the contract by requesting a random number from the entropy provider. -/// The entropy provider will then fulfill the request by revealing their random number. -/// Once the provider has fulfilled their request the entropy contract will call back -/// the requesting contract with the generated random number. -/// -/// The CoinFlip contract implements the IEntropyConsumer interface imported from the Solidity SDK. -/// The interface helps in integrating with Entropy correctly. -contract CoinFlip is IEntropyConsumer { - // Event emitted when a coin flip is requested. The sequence number can be used to identify a request - event FlipRequest(uint64 sequenceNumber); - - // Event emitted when the result of the coin flip is known. - event FlipResult(uint64 sequenceNumber, bool isHeads); - - // Contracts using Pyth Entropy should import the solidity SDK and then store both the Entropy contract - // and a specific entropy provider to use for requests. Each provider commits to a sequence of random numbers. - // Providers are then responsible for fulfilling a request on chain by revealing their random number. - // Users should choose a reliable provider who they trust to uphold these commitments. - // (For the moment, the only available provider is 0x6CC14824Ea2918f5De5C2f75A9Da968ad4BD6344) - IEntropy private entropy; - address private entropyProvider; - - constructor(address _entropy, address _entropyProvider) { - entropy = IEntropy(_entropy); - entropyProvider = _entropyProvider; - } - - // Request to flip a coin. The caller should generate and pass in a random number when calling this method. - function requestFlip(bytes32 userRandomNumber) external payable { - // The entropy protocol requires the caller to pay a fee (in native gas tokens) per requested random number. - // This fee can either be paid by the contract itself or passed on to the end user. - // This implementation of the requestFlip method passes on the fee to the end user. - uint256 fee = entropy.getFee(entropyProvider); - if (msg.value < fee) { - revert CoinFlipErrors.InsufficientFee(); - } - - // Request the random number from the Entropy protocol. The call returns a sequence number that uniquely - // identifies the generated random number. Callers can use this sequence number to match which request - // is being revealed in the next stage of the protocol. - uint64 sequenceNumber = entropy.requestWithCallback{value: fee}( - entropyProvider, - userRandomNumber - ); - - emit FlipRequest(sequenceNumber); - } - - // Get the fee to flip a coin. See the comment above about fees. - function getFlipFee() public view returns (uint256 fee) { - fee = entropy.getFee(entropyProvider); - } - - // This method is required by the IEntropyConsumer interface. - // It is called by the entropy contract when a random number is generated. - function entropyCallback( - uint64 sequenceNumber, - // If your app uses multiple providers, you can use this argument - // to distinguish which one is calling the app back. This app only - // uses one provider so this argument is not used. - address, - bytes32 randomNumber - ) internal override { - emit FlipResult(sequenceNumber, uint256(randomNumber) % 2 == 0); - } - - // This method is required by the IEntropyConsumer interface. - // It returns the address of the entropy contract which will call the callback. - function getEntropy() internal view override returns (address) { - return address(entropy); - } - - receive() external payable {} -}