[entropy] Typescript code for coin flip example + docs (#1128)

* adding stuff

* add coin flip example

* it works

* docs

* hm

* pr comments
This commit is contained in:
Jayant Krishnamurthy 2023-11-01 10:30:04 -07:00 committed by GitHub
parent f0a077a2cf
commit f36e868ef6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 645 additions and 4 deletions

224
package-lock.json generated
View File

@ -20,6 +20,7 @@
"target_chains/ethereum/entropy_sdk/solidity",
"target_chains/ethereum/sdk/js",
"target_chains/ethereum/sdk/solidity",
"target_chains/ethereum/examples/coin_flip/app",
"target_chains/ethereum/examples/oracle_swap/app",
"target_chains/sui/sdk/js",
"target_chains/sui/cli",
@ -11760,6 +11761,10 @@
"resolved": "target_chains/ethereum/entropy_sdk/solidity",
"link": true
},
"node_modules/@pythnetwork/eth-coin-flip-example": {
"resolved": "target_chains/ethereum/examples/coin_flip/app",
"link": true
},
"node_modules/@pythnetwork/eth-oracle-swap-example-frontend": {
"resolved": "target_chains/ethereum/examples/oracle_swap/app",
"link": true
@ -57995,6 +58000,7 @@
}
},
"target_chains/ethereum/entropy_sdk/solidity": {
"name": "@pythnetwork/entropy-sdk-solidity",
"version": "0.1.0",
"license": "Apache-2.0",
"devDependencies": {
@ -58042,6 +58048,133 @@
"node": ">=10.0.0"
}
},
"target_chains/ethereum/examples/coin_flip/app": {
"name": "@pythnetwork/eth-coin-flip-example",
"version": "0.1.0",
"dependencies": {
"@pythnetwork/pyth-evm-js": "*",
"@pythnetwork/pyth-sdk-solidity": "*",
"@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"
},
"devDependencies": {
"ts-node": "^10.9.1"
}
},
"target_chains/ethereum/examples/coin_flip/app/node_modules/@types/jest": {
"version": "27.5.2",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz",
"integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==",
"dependencies": {
"jest-matcher-utils": "^27.0.0",
"pretty-format": "^27.0.0"
}
},
"target_chains/ethereum/examples/coin_flip/app/node_modules/@types/node": {
"version": "16.18.60",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.60.tgz",
"integrity": "sha512-ZUGPWx5vKfN+G2/yN7pcSNLkIkXEvlwNaJEd4e0ppX7W2S8XAkdc/37hM4OUNJB9sa0p12AOvGvxL4JCPiz9DA=="
},
"target_chains/ethereum/examples/coin_flip/app/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"target_chains/ethereum/examples/coin_flip/app/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"target_chains/ethereum/examples/coin_flip/app/node_modules/diff-sequences": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz",
"integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==",
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"target_chains/ethereum/examples/coin_flip/app/node_modules/jest-diff": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz",
"integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==",
"dependencies": {
"chalk": "^4.0.0",
"diff-sequences": "^27.5.1",
"jest-get-type": "^27.5.1",
"pretty-format": "^27.5.1"
},
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"target_chains/ethereum/examples/coin_flip/app/node_modules/jest-get-type": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz",
"integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==",
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"target_chains/ethereum/examples/coin_flip/app/node_modules/jest-matcher-utils": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz",
"integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==",
"dependencies": {
"chalk": "^4.0.0",
"jest-diff": "^27.5.1",
"jest-get-type": "^27.5.1",
"pretty-format": "^27.5.1"
},
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"target_chains/ethereum/examples/coin_flip/app/node_modules/pretty-format": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
"react-is": "^17.0.1"
},
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"target_chains/ethereum/examples/coin_flip/app/node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
"target_chains/ethereum/examples/oracle_swap/app": {
"name": "@pythnetwork/eth-oracle-swap-example-frontend",
"version": "0.1.0",
@ -66441,6 +66574,97 @@
}
}
},
"@pythnetwork/eth-coin-flip-example": {
"version": "file:target_chains/ethereum/examples/coin_flip/app",
"requires": {
"@pythnetwork/pyth-evm-js": "*",
"@pythnetwork/pyth-sdk-solidity": "*",
"@types/jest": "^27.5.2",
"@types/node": "^16.11.64",
"buffer": "^6.0.3",
"ethers": "^5.7.2",
"prettier": "^2.7.1",
"ts-node": "^10.9.1",
"typescript": "^4.8.4"
},
"dependencies": {
"@types/jest": {
"version": "27.5.2",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz",
"integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==",
"requires": {
"jest-matcher-utils": "^27.0.0",
"pretty-format": "^27.0.0"
}
},
"@types/node": {
"version": "16.18.60",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.60.tgz",
"integrity": "sha512-ZUGPWx5vKfN+G2/yN7pcSNLkIkXEvlwNaJEd4e0ppX7W2S8XAkdc/37hM4OUNJB9sa0p12AOvGvxL4JCPiz9DA=="
},
"ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
},
"buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"diff-sequences": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz",
"integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ=="
},
"jest-diff": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz",
"integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==",
"requires": {
"chalk": "^4.0.0",
"diff-sequences": "^27.5.1",
"jest-get-type": "^27.5.1",
"pretty-format": "^27.5.1"
}
},
"jest-get-type": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz",
"integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw=="
},
"jest-matcher-utils": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz",
"integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==",
"requires": {
"chalk": "^4.0.0",
"jest-diff": "^27.5.1",
"jest-get-type": "^27.5.1",
"pretty-format": "^27.5.1"
}
},
"pretty-format": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"requires": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
"react-is": "^17.0.1"
}
},
"react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
}
}
},
"@pythnetwork/eth-oracle-swap-example-frontend": {
"version": "file:target_chains/ethereum/examples/oracle_swap/app",
"requires": {

View File

@ -15,6 +15,7 @@
"target_chains/ethereum/entropy_sdk/solidity",
"target_chains/ethereum/sdk/js",
"target_chains/ethereum/sdk/solidity",
"target_chains/ethereum/examples/coin_flip/app",
"target_chains/ethereum/examples/oracle_swap/app",
"target_chains/sui/sdk/js",
"target_chains/sui/cli",

View File

@ -0,0 +1,81 @@
# Pyth Entropy Solidity SDK
The Pyth Entropy Solidity SDK allows you to generate secure random numbers on the blockchain by
interacting with the Pyth Entropy protocol.
This SDK can be used for any application that requires random numbers, such as NFT mints, gaming, and more.
**WARNING**: The Entropy protocol is currently in testnet. It is **NOT INTENDED** for use in production applications.
Use this protocol at your own risk.
## Install
TODO
## Setup
To use the SDK, you need the address of an Entropy contract on your blockchain and a randomness provider.
The following table lists the current deployments of entropy.
| Chain | Entropy Address | Provider |
| avalanche-fuji | 0xD42c7a708E74AD19401D907a14146F006c851Ee3 | 0x368397bDc956b4F23847bE244f350Bde4615F25E
| optimism-goerli | 0x28F16Af4D87523910b843a801454AEde5F9B0459 | 0x368397bDc956b4F23847bE244f350Bde4615F25E
| eos-evm-testnet | 0xD42c7a708E74AD19401D907a14146F006c851Ee3 | 0x368397bDc956b4F23847bE244f350Bde4615F25E
Choose one of these networks and instantiate an `IEntropy` contract in your solidity contract:
```solidity
IEntropy entropy = IEntropy(<address>);
```
## Usage
To generate a random number, follow these steps.
### 1. Commit to a random number
Generate a 32-byte random number on the client side, then hash it with keccak256 to create a commitment.
You can do this with typescript and web3.js as follows:
```typescript
const randomNumber = web3.utils.randomHex(32);
const commitment = web3.utils.keccak256(randomNumber);
```
### 2. Request a number from Entropy
Invoke the `request` method of the `IEntropy` contract:
```solidity
uint64 sequenceNumber = entropy.request(provider, commitment, true)
```
This method returns a sequence number. Store this sequence number for use in later steps.
If you are invoking this off-chain, the method also emits a `PythRandomEvents.Requested` event that contains the sequence number in it.
### 3. Fetch the provider's number
Fetch the provider's random number from them.
For the provider `0x368397bDc956b4F23847bE244f350Bde4615F25E` you can query the webservice at https://fortuna-staging.pyth.network :
```typescript
await axios.get(
`https://fortuna-staging.pyth.network/v1/chains/${chainName}/revelations/${sequenceNumber}`
);
```
This method returns a JSON object containing the provider's random number.
### 4. Reveal the number
Invoke the `reveal` method on the `IEntropy` contract:
```solidity
bytes32 randomNumber = entropy.reveal(
provider,
sequenceNumber,
randomNumber,
providerRandomNumber
)
```
This method will combine the user and provider's random numbers, along with the blockhash, to construct the final secure random number.

View File

@ -0,0 +1,57 @@
# 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
npm install
npx 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-goerli | 0x075A5160FF6462924B4124595F6f987187496476 | https://goerli.optimism.io |
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 <hexadecimal evm private key> \
--chain-name <chain name> \
--address <address> \
--rpc-url <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 : 0x79b029406af43b11937bca98c49633f9382ed7d3fc0d60e110258c5c8f0d1a05
commitment: 0xd4bca63083f9fb9e83e68348cb48f45babd820fc3559c60ba9a67b0ab3845cea
2. Requesting coin flip...
fee : 87 wei
tx : 0x3a59bb8c1aaa8c6ff97147bb3197e9b89c0d87174b0b6c32374fc62de6d8db94
sequence : 50
3. Retrieving provider's random number...
fetch url : https://fortuna-staging.pyth.network/v1/chains/optimism-goerli/revelations/50
number : 0x760e53a19a4677ef671fde63db59462dfb3e09e94418e9962e2fa764026b8400
4. Revealing the result of the coin flip...
tx : 0x0549b93b12684187f73ddcaf8351ca4049867882c1b138989e15363a4d103220
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.

View File

@ -0,0 +1,4 @@
node_modules
lib
.dccache
*mnemonic*

View File

@ -0,0 +1,23 @@
{
"name": "@pythnetwork/eth-coin-flip-example",
"version": "0.1.0",
"private": true,
"dependencies": {
"@pythnetwork/pyth-evm-js": "*",
"@pythnetwork/pyth-sdk-solidity": "*",
"@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"
},
"devDependencies": {
"ts-node": "^10.9.1"
},
"scripts": {
"build": "tsc",
"flip-coin": "npm run build && node lib/flip_coin.js",
"format": "prettier --write src/"
}
}

View File

@ -0,0 +1,107 @@
[
{
"inputs": [
{
"internalType": "address",
"name": "_entropy",
"type": "address"
},
{
"internalType": "address",
"name": "_entropyProvider",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "IncorrectSender",
"type": "error"
},
{
"inputs": [],
"name": "InsufficientFee",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint64",
"name": "sequenceNumber",
"type": "uint64"
}
],
"name": "FlipRequest",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "bool",
"name": "isHeads",
"type": "bool"
}
],
"name": "FlipResult",
"type": "event"
},
{
"inputs": [],
"name": "getFlipFee",
"outputs": [
{
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "userCommitment",
"type": "bytes32"
}
],
"name": "requestFlip",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "sequenceNumber",
"type": "uint64"
},
{
"internalType": "bytes32",
"name": "userRandom",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "providerRandom",
"type": "bytes32"
}
],
"name": "revealFlip",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]

View File

@ -0,0 +1,123 @@
import Web3 from "web3";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import HDWalletProvider from "@truffle/hdwallet-provider";
import CoinFlipAbi from "./CoinFlipAbi.json";
import axios from "axios";
const argv = yargs(hideBin(process.argv))
.option("private-key", {
description: "Private key (as a hexadecimal string) of the sender",
type: "string",
required: true,
})
.option("fortuna-url", {
description: "URL of the fortuna server for your chosen provider",
type: "string",
default: "https://fortuna-staging.pyth.network",
})
.option("chain-name", {
description:
"The name of your blockchain (for accessing data from fortuna)",
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,
})
.parseSync();
const fortunaUrl = argv.fortunaUrl;
const chainName = argv.chainName;
const coinFlipContractAddress = argv.address;
const rpc = argv.rpcUrl;
const privateKey = argv.privateKey;
async function fetchWithRetry(url: string, maxRetries: number): Promise<any> {
let retryCount = 0;
async function doRequest() {
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
if (retryCount < maxRetries) {
retryCount++;
setTimeout(doRequest, 1000);
} else {
console.error("Max retry attempts reached. Exiting.");
throw error;
}
}
}
return await doRequest(); // Start the initial request
}
async function main() {
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);
const commitment = web3.utils.keccak256(randomNumber);
console.log(` number : ${randomNumber}`);
console.log(` commitment: ${commitment}`);
console.log("2. Requesting coin flip...");
const flipFee = await coinFlipContract.methods.getFlipFee().call();
console.log(` fee : ${flipFee} wei`);
const receipt = await coinFlipContract.methods
.requestFlip(commitment)
.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. Retrieving provider's random number...");
const url = `${fortunaUrl}/v1/chains/${chainName}/revelations/${sequenceNumber}`;
console.log(` fetch url : ${url}`);
// Note that there is a potential race condition here: the server may not have observed the request ^
// before this HTTP response. Hence, we retry fetching the url a couple of times.
const response = await fetchWithRetry(url, 3);
const providerRandom = web3.utils.bytesToHex(response.value);
console.log(` number : ${providerRandom}`);
console.log("4. Revealing the result of the coin flip...");
const receipt2 = await coinFlipContract.methods
.revealFlip(sequenceNumber, randomNumber, providerRandom)
.send({ from: provider.getAddress(0) });
console.log(` tx : ${receipt2.transactionHash}`);
const isHeads = receipt2.events.FlipResult.returnValues.isHeads;
console.log(` result : ${isHeads ? "heads" : "tails"}`);
provider.engine.stop();
}
main();

View File

@ -0,0 +1,15 @@
{
"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"]
}

View File

@ -1,14 +1,14 @@
#!/bin/bash -e
# URL of the ethereum RPC node to use. Choose this based on your target network
RPC_URL=https://api.avax-test.network/ext/bc/C/rpc
RPC_URL=https://goerli.optimism.io
# 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="0xD42c7a708E74AD19401D907a14146F006c851Ee3"
ENTROPY_CONTRACT_ADDRESS="0x28F16Af4D87523910b843a801454AEde5F9B0459"
PROVIDER="0x368397bDc956b4F23847bE244f350Bde4615F25E"
# Avalanche fuji address:
# 0x544c5ab499C38dff495724451783F63a3eeA40F2
# Deployed contracts
# Optimism goerli 0x075A5160FF6462924B4124595F6f987187496476
# 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.

View File

@ -1,6 +1,7 @@
// 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";
library CoinFlipErrors {
@ -73,6 +74,11 @@ contract CoinFlip {
emit FlipRequest(sequenceNumber);
}
// Get the fee to flip a coin. See the comment above about fees.
function getFlipFee() public returns (uint256 fee) {
fee = entropy.getFee(entropyProvider);
}
// Reveal the result of the coin flip. The caller must have an in-flight request for a coin flip, which is
// identified by `sequenceNumber`. The caller must additionally provide the random number that they previously
// committed to, as well as the entropy provider's random number. The provider's random number can be retrieved