add evm example
This commit is contained in:
parent
7cf7420203
commit
56b8b0abbd
|
@ -17,6 +17,7 @@
|
|||
"target_chains/cosmwasm/tools",
|
||||
"target_chains/cosmwasm/deploy-scripts",
|
||||
"target_chains/ethereum/contracts",
|
||||
"target_chains/ethereum/entropy_sdk/js",
|
||||
"target_chains/ethereum/entropy_sdk/solidity",
|
||||
"target_chains/ethereum/sdk/js",
|
||||
"target_chains/ethereum/sdk/solidity",
|
||||
|
@ -11758,6 +11759,10 @@
|
|||
"resolved": "target_chains/cosmwasm/tools",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@pythnetwork/entropy-sdk-js": {
|
||||
"resolved": "target_chains/ethereum/entropy_sdk/js",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@pythnetwork/entropy-sdk-solidity": {
|
||||
"resolved": "target_chains/ethereum/entropy_sdk/solidity",
|
||||
"link": true
|
||||
|
@ -29872,7 +29877,6 @@
|
|||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz",
|
||||
"integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build": "^4.3.0"
|
||||
|
@ -30202,7 +30206,6 @@
|
|||
"version": "5.0.7",
|
||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz",
|
||||
"integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build": "^4.3.0"
|
||||
|
@ -58002,9 +58005,99 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"target_chains/ethereum/entropy_sdk/js": {
|
||||
"version": "0.0.1",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@pythnetwork/price-service-client": "*",
|
||||
"buffer": "^6.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@pythnetwork/entropy-sdk-solidity": "*",
|
||||
"@truffle/hdwallet-provider": "^2.1.5",
|
||||
"@types/ethereum-protocol": "^1.0.2",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/web3-provider-engine": "^14.0.1",
|
||||
"@types/yargs": "^17.0.10",
|
||||
"@typescript-eslint/eslint-plugin": "^5.21.0",
|
||||
"@typescript-eslint/parser": "^5.21.0",
|
||||
"eslint": "^8.14.0",
|
||||
"jest": "^29.4.1",
|
||||
"prettier": "^2.6.2",
|
||||
"ts-jest": "^29.0.5",
|
||||
"typescript": "^4.6.3",
|
||||
"web3": "^1.8.2",
|
||||
"yargs": "^17.4.1"
|
||||
}
|
||||
},
|
||||
"target_chains/ethereum/entropy_sdk/js/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/entropy_sdk/js/node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"target_chains/ethereum/entropy_sdk/js/node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"target_chains/ethereum/entropy_sdk/js/node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"target_chains/ethereum/entropy_sdk/solidity": {
|
||||
"name": "@pythnetwork/entropy-sdk-solidity",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"prettier": "^2.7.1",
|
||||
|
@ -66540,6 +66633,72 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@pythnetwork/entropy-sdk-js": {
|
||||
"version": "file:target_chains/ethereum/entropy_sdk/js",
|
||||
"requires": {
|
||||
"@pythnetwork/entropy-sdk-solidity": "*",
|
||||
"@pythnetwork/price-service-client": "*",
|
||||
"@truffle/hdwallet-provider": "^2.1.5",
|
||||
"@types/ethereum-protocol": "^1.0.2",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/web3-provider-engine": "^14.0.1",
|
||||
"@types/yargs": "^17.0.10",
|
||||
"@typescript-eslint/eslint-plugin": "^5.21.0",
|
||||
"@typescript-eslint/parser": "^5.21.0",
|
||||
"buffer": "^6.0.3",
|
||||
"eslint": "^8.14.0",
|
||||
"jest": "^29.4.1",
|
||||
"prettier": "^2.6.2",
|
||||
"ts-jest": "^29.0.5",
|
||||
"typescript": "^4.6.3",
|
||||
"web3": "^1.8.2",
|
||||
"yargs": "^17.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@pythnetwork/entropy-sdk-solidity": {
|
||||
"version": "file:target_chains/ethereum/entropy_sdk/solidity",
|
||||
"requires": {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"target_chains/cosmwasm/tools",
|
||||
"target_chains/cosmwasm/deploy-scripts",
|
||||
"target_chains/ethereum/contracts",
|
||||
"target_chains/ethereum/entropy_sdk/js",
|
||||
"target_chains/ethereum/entropy_sdk/solidity",
|
||||
"target_chains/ethereum/sdk/js",
|
||||
"target_chains/ethereum/sdk/solidity",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
node_modules
|
||||
lib
|
||||
.dccache
|
||||
*mnemonic*
|
|
@ -0,0 +1,170 @@
|
|||
# Pyth EVM JS
|
||||
|
||||
[Pyth](https://pyth.network/) provides real-time pricing data in a variety of asset classes, including cryptocurrency,
|
||||
equities, FX and commodities. This library allows you to use these real-time prices on EVM-based networks.
|
||||
|
||||
## Installation
|
||||
|
||||
### npm
|
||||
|
||||
```
|
||||
$ npm install --save @pythnetwork/pyth-evm-js
|
||||
```
|
||||
|
||||
### Yarn
|
||||
|
||||
```
|
||||
$ yarn add @pythnetwork/pyth-evm-js
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
|
||||
Pyth stores prices off-chain to minimize gas fees, which allows us to offer a wider selection of products and faster
|
||||
update times. See [On-Demand Updates](https://docs.pyth.network/documentation/pythnet-price-feeds/on-demand) for more
|
||||
information about this approach. In order to use Pyth prices on chain, they must be fetched from an off-chain Hermes
|
||||
instance. The `EvmPriceServiceConnection` class can be used to interact with these services, providing a way to fetch
|
||||
these prices directly in your code. The following example wraps an existing RPC provider and shows how to obtain Pyth
|
||||
prices and submit them to the network:
|
||||
|
||||
```typescript
|
||||
const connection = new EvmPriceServiceConnection("https://hermes.pyth.network"); // See Hermes endpoints section below for other endpoints
|
||||
|
||||
const priceIds = [
|
||||
// You can find the ids of prices at https://pyth.network/developers/price-feed-ids#pyth-evm-stable
|
||||
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", // BTC/USD price id
|
||||
"0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", // ETH/USD price id
|
||||
];
|
||||
|
||||
// In order to use Pyth prices in your protocol you need to submit the price update data to Pyth contract in your target
|
||||
// chain. `getPriceFeedsUpdateData` creates the update data which can be submitted to your contract. Then your contract should
|
||||
// call the Pyth Contract with this data.
|
||||
const priceUpdateData = await connection.getPriceFeedsUpdateData(priceIds);
|
||||
|
||||
// If the user is paying the price update fee, you need to fetch it from the Pyth contract.
|
||||
// Please refer to https://docs.pyth.network/documentation/pythnet-price-feeds/on-demand#fees for more information.
|
||||
//
|
||||
// `pythContract` below is a web3.js contract; if you wish to use ethers, you need to change it accordingly.
|
||||
// You can find the Pyth interface ABI in @pythnetwork/pyth-sdk-solidity npm package.
|
||||
const updateFee = await pythContract.methods
|
||||
.getUpdateFee(priceUpdateData)
|
||||
.call();
|
||||
// Calling someContract method
|
||||
// `someContract` below is a web3.js contract; if you wish to use ethers, you need to change it accordingly.
|
||||
await someContract.methods
|
||||
.doSomething(someArg, otherArg, priceUpdateData)
|
||||
.send({ value: updateFee });
|
||||
```
|
||||
|
||||
`SomeContract` looks like so:
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "@pythnetwork/pyth-sdk-solidity/IPyth.sol";
|
||||
import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol";
|
||||
|
||||
contract SomeContract {
|
||||
IPyth pyth;
|
||||
|
||||
constructor(address pythContract) {
|
||||
pyth = IPyth(pythContract);
|
||||
}
|
||||
|
||||
function doSomething(
|
||||
uint someArg,
|
||||
string memory otherArg,
|
||||
bytes[] calldata priceUpdateData
|
||||
) public payable {
|
||||
// Update the prices to be set to the latest values
|
||||
uint fee = pyth.getUpdateFee(priceUpdateData);
|
||||
pyth.updatePriceFeeds{ value: fee }(priceUpdateData);
|
||||
|
||||
// Doing other things that uses prices
|
||||
bytes32 priceId = 0xf9c0172ba10dfa4d19088d94f5bf61d3b54d5bd7483a322a982e1373ee8ea31b;
|
||||
PythStructs.Price price = pyth.getPrice(priceId);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
We strongly recommend reading our guide which explains [how to work with Pyth price feeds](https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices).
|
||||
|
||||
### Off-chain prices
|
||||
|
||||
Many applications additionally need to display Pyth prices off-chain, for example, in their frontend application.
|
||||
The `EvmPriceServiceConnection` provides two different ways to fetch the current Pyth price.
|
||||
The code blocks below assume that the `connection` and `priceIds` objects have been initialized as shown above.
|
||||
The first method is a single-shot query:
|
||||
|
||||
```typescript
|
||||
// `getLatestPriceFeeds` returns a `PriceFeed` for each price id. It contains all information about a price and has
|
||||
// utility functions to get the current and exponentially-weighted moving average price, and other functionality.
|
||||
const priceFeeds = await connection.getLatestPriceFeeds(priceIds);
|
||||
// Get the price if it is not older than 60 seconds from the current time.
|
||||
console.log(priceFeeds[0].getPriceNoOlderThan(60)); // Price { conf: '1234', expo: -8, price: '12345678' }
|
||||
// Get the exponentially-weighted moving average price if it is not older than 60 seconds from the current time.
|
||||
console.log(priceFeeds[1].getEmaPriceNoOlderThan(60));
|
||||
```
|
||||
|
||||
The object also supports a streaming websocket connection that allows you to subscribe to every new price update for a given feed.
|
||||
This method is useful if you want to show continuously updating real-time prices in your frontend:
|
||||
|
||||
```typescript
|
||||
// Subscribe to the price feeds given by `priceId`. The callback will be invoked every time the requested feed
|
||||
// gets a price update.
|
||||
connection.subscribePriceFeedUpdates(priceIds, (priceFeed) => {
|
||||
console.log(
|
||||
`Received update for ${priceFeed.id}: ${priceFeed.getPriceNoOlderThan(60)}`
|
||||
);
|
||||
});
|
||||
|
||||
// When using the subscription, make sure to close the websocket upon termination to finish the process gracefully.
|
||||
setTimeout(() => {
|
||||
connection.closeWebSocket();
|
||||
}, 60000);
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
There are two examples in [examples](./src/examples/).
|
||||
|
||||
#### EvmPriceServiceClient
|
||||
|
||||
[This example](./src/examples/EvmPriceServiceClient.ts) fetches `PriceFeed` updates using both a HTTP-request API and a streaming websocket API. You can run it with `npm run example-client`. A full command that prints BTC and ETH price feeds, in the testnet network, looks like so:
|
||||
|
||||
```bash
|
||||
npm run example-client -- \
|
||||
--endpoint https://hermes.pyth.network \
|
||||
--price-ids \
|
||||
0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43 \
|
||||
0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace
|
||||
```
|
||||
|
||||
#### EvmRelay
|
||||
|
||||
[This example](./src/examples/EvmRelay.ts) shows how to update prices on an EVM network. It does the following:
|
||||
|
||||
1. Gets update data to update given price feeds.
|
||||
2. Calls the pyth contract with the update data.
|
||||
3. Submits it to the network and prints the txhash if successful.
|
||||
|
||||
You can run this example with `npm run example-relay`. A full command that updates BTC and ETH prices on the BNB Chain
|
||||
testnet network looks like so:
|
||||
|
||||
```bash
|
||||
npm run example-relay -- \
|
||||
--network "https://data-seed-prebsc-1-s1.binance.org:8545" \
|
||||
--pyth-contract "0x5744Cbf430D99456a0A8771208b674F27f8EF0Fb"\
|
||||
--mnemonic "my good mnemonic" \
|
||||
--endpoint https://hermes.pyth.network \
|
||||
--price-ids \
|
||||
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43" \
|
||||
"0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace"
|
||||
```
|
||||
|
||||
## Hermes endpoints
|
||||
|
||||
Pyth offers a free public endpoint at [https://hermes.pyth.network](https://hermes.pyth.network). However, it is
|
||||
recommended to obtain a private endpoint from one of the Hermes RPC providers for more reliability. You can find more
|
||||
information about Hermes RPC providers
|
||||
[here](https://docs.pyth.network/documentation/pythnet-price-feeds/hermes#public-endpoint).
|
|
@ -0,0 +1,5 @@
|
|||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
};
|
|
@ -0,0 +1,59 @@
|
|||
{
|
||||
"name": "@pythnetwork/entropy-sdk-js",
|
||||
"version": "0.0.1",
|
||||
"description": "Pyth Network Javascript Entropy SDK",
|
||||
"homepage": "https://pyth.network",
|
||||
"author": {
|
||||
"name": "Pyth Data Association"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"files": [
|
||||
"lib/**/*"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pyth-network/pyth-crosschain",
|
||||
"directory": "target_chains/ethereum/entropy_sdk/js"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest --passWithNoTests",
|
||||
"build": "tsc",
|
||||
"evm-example": "npm run build && node lib/examples/EvmRandomDraw.js",
|
||||
"format": "prettier --write \"src/**/*.ts\"",
|
||||
"lint": "eslint src/",
|
||||
"prepublishOnly": "npm run build && npm test && npm run lint",
|
||||
"preversion": "npm run lint",
|
||||
"version": "npm run format && git add -A src"
|
||||
},
|
||||
"keywords": [
|
||||
"pyth",
|
||||
"oracle"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@pythnetwork/entropy-sdk-solidity": "*",
|
||||
"@truffle/hdwallet-provider": "^2.1.5",
|
||||
"@types/ethereum-protocol": "^1.0.2",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/web3-provider-engine": "^14.0.1",
|
||||
"@types/yargs": "^17.0.10",
|
||||
"@typescript-eslint/eslint-plugin": "^5.21.0",
|
||||
"@typescript-eslint/parser": "^5.21.0",
|
||||
"eslint": "^8.14.0",
|
||||
"jest": "^29.4.1",
|
||||
"prettier": "^2.6.2",
|
||||
"ts-jest": "^29.0.5",
|
||||
"typescript": "^4.6.3",
|
||||
"web3": "^1.8.2",
|
||||
"yargs": "^17.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.5.1",
|
||||
"axios-retry": "^3.8.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import axios, { AxiosInstance } from "axios";
|
||||
import axiosRetry from "axios-retry";
|
||||
|
||||
export class FortunaConnection {
|
||||
private httpClient: AxiosInstance;
|
||||
|
||||
constructor(endpoint: string) {
|
||||
this.httpClient = axios.create({
|
||||
baseURL: endpoint,
|
||||
timeout: 5000,
|
||||
// timeout: config?.timeout || 5000,
|
||||
});
|
||||
axiosRetry(this.httpClient, {
|
||||
// retries: config?.httpRetries || 3,
|
||||
retries: 3,
|
||||
retryDelay: axiosRetry.exponentialDelay,
|
||||
});
|
||||
}
|
||||
|
||||
async retrieveRandomNumber(sequenceNumber: any) {
|
||||
const response = await this.httpClient.get(
|
||||
`/revelations/${sequenceNumber}`
|
||||
);
|
||||
return response.data.value.data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
import Web3 from "web3";
|
||||
import yargs from "yargs";
|
||||
import { hideBin } from "yargs/helpers";
|
||||
|
||||
import HDWalletProvider from "@truffle/hdwallet-provider";
|
||||
import IEntropy from "@pythnetwork/entropy-sdk-solidity/abis/IEntropy.json";
|
||||
import { FortunaConnection } from "../index";
|
||||
|
||||
const argv = yargs(hideBin(process.argv))
|
||||
.option("network", {
|
||||
description: "RPC for the network to relay on.",
|
||||
type: "string",
|
||||
required: true,
|
||||
})
|
||||
.option("fortuna-url", {
|
||||
description: "URL for Fortuna. e.g: https://endpoint/example",
|
||||
type: "string",
|
||||
required: true,
|
||||
})
|
||||
.option("contract", {
|
||||
description: "Entropy contract address.",
|
||||
type: "string",
|
||||
required: true,
|
||||
})
|
||||
.option("provider", {
|
||||
description:
|
||||
"The randomness provider to query" + " e.g: 0xf9c0172ba10dfa4d19088d...",
|
||||
type: "string",
|
||||
required: true,
|
||||
})
|
||||
.option("mnemonic", {
|
||||
description: "Mnemonic (private key) for sender",
|
||||
type: "string",
|
||||
required: true,
|
||||
})
|
||||
.help()
|
||||
.alias("help", "h")
|
||||
.parserConfiguration({
|
||||
"parse-numbers": false,
|
||||
})
|
||||
.parseSync();
|
||||
|
||||
const network = argv.network;
|
||||
const provider = argv.provider;
|
||||
const fortunaUrl = argv.fortunaUrl;
|
||||
|
||||
// const url = `${fortunaUrl}/v1/chains/${chainName}/revelations/${sequenceNumber}`;
|
||||
const connection = new FortunaConnection(argv.fortunaUrl);
|
||||
|
||||
async function run() {
|
||||
const walletProvider = new HDWalletProvider({
|
||||
mnemonic: {
|
||||
phrase: argv.mnemonic,
|
||||
},
|
||||
providerOrUrl: network,
|
||||
});
|
||||
console.log(`wallet address: ${walletProvider.getAddress(0)}`);
|
||||
|
||||
// @ts-ignore
|
||||
const web3 = new Web3(walletProvider);
|
||||
|
||||
const userRandom = web3.utils.randomHex(32);
|
||||
console.log(`userRandom: ${userRandom}`);
|
||||
const commitment = web3.utils.keccak256(userRandom);
|
||||
|
||||
const entropy = new web3.eth.Contract(IEntropy as any, argv.contract);
|
||||
|
||||
console.log("1. getFee");
|
||||
const fee = await entropy.methods.getFee(provider).call();
|
||||
console.log("2. request");
|
||||
const receipt = await entropy.methods
|
||||
.request(provider, commitment, true)
|
||||
.send({ value: fee, from: walletProvider.getAddress(0) });
|
||||
console.log(` tx : ${receipt.transactionHash}`);
|
||||
const sequenceNumber =
|
||||
receipt.events.Requested.returnValues.request.sequenceNumber;
|
||||
const blockNumber = receipt.events.Requested.returnValues.request.blockNumber;
|
||||
console.log(` sequence : ${sequenceNumber}`);
|
||||
console.log(` block : ${blockNumber}`);
|
||||
|
||||
console.log("3. Retrieving provider's random number...");
|
||||
const providerRandomHex = await connection.retrieveRandomNumber(
|
||||
sequenceNumber
|
||||
);
|
||||
const providerRandom = `0x${providerRandomHex}`;
|
||||
console.log(` number : ${providerRandom}`);
|
||||
|
||||
let blockFinalized = false;
|
||||
while (!blockFinalized) {
|
||||
try {
|
||||
const block = await web3.eth.getBlock("latest");
|
||||
console.log(`current block number: ${block.number}`);
|
||||
if (block.number > blockNumber) {
|
||||
blockFinalized = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Waiting for block to finalize");
|
||||
await new Promise((f) => setTimeout(f, 500));
|
||||
}
|
||||
}
|
||||
|
||||
const receipt2 = await entropy.methods
|
||||
.reveal(provider, sequenceNumber, userRandom, providerRandom)
|
||||
.send({ from: walletProvider.getAddress(0) });
|
||||
console.log(` tx : ${receipt2.transactionHash}`);
|
||||
const randomNumber = receipt2.events.Revealed.returnValues.randomNumber;
|
||||
console.log(` result : ${randomNumber}`);
|
||||
|
||||
walletProvider.engine.stop();
|
||||
}
|
||||
|
||||
async function tryReveal() {}
|
||||
|
||||
run();
|
|
@ -0,0 +1,82 @@
|
|||
export { FortunaConnection } from "./FortunaConnection";
|
||||
|
||||
export const CONTRACT_ADDR: Record<string, string> = {
|
||||
// Mainnets
|
||||
arbitrum: "0xff1a0f4744e8582DF1aE09D5611b887B6a12925C",
|
||||
aurora: "0xF89C7b475821EC3fDC2dC8099032c05c6c0c9AB9",
|
||||
avalanche: "0x4305FB66699C3B2702D4d05CF36551390A4c69C6",
|
||||
bnb: "0x4D7E825f80bDf85e913E0DD2A2D54927e9dE1594",
|
||||
base: "0x8250f4aF4B972684F7b336503E2D6dFeDeB1487a",
|
||||
boba: "0x4374e5a8b9C22271E9EB878A2AA31DE97DF15DAF",
|
||||
bttc: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
canto: "0x98046Bd286715D3B0BC227Dd7a956b83D8978603",
|
||||
celo: "0xff1a0f4744e8582DF1aE09D5611b887B6a12925C",
|
||||
chiliz: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
conflux_espace: "0xe9d69CdD6Fe41e7B621B4A688C5D1a68cB5c8ADc",
|
||||
core_dao: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
cronos: "0xE0d0e68297772Dd5a1f1D99897c581E2082dbA5B",
|
||||
eos: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
evmos: "0x354bF866A4B006C9AF9d9e06d9364217A8616E12",
|
||||
ethereum: "0x4305FB66699C3B2702D4d05CF36551390A4c69C6",
|
||||
fantom: "0xff1a0f4744e8582DF1aE09D5611b887B6a12925C",
|
||||
gnosis: "0x2880aB155794e7179c9eE2e38200202908C17B43",
|
||||
horizen_eon: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
kava: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
linea: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
manta: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
mantle: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
meter: "0xbFe3f445653f2136b2FD1e6DdDb5676392E3AF16",
|
||||
mode: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
neon: "0x7f2dB085eFC3560AFF33865dD727225d91B4f9A5",
|
||||
optimism: "0xff1a0f4744e8582DF1aE09D5611b887B6a12925C",
|
||||
polygon: "0xff1a0f4744e8582DF1aE09D5611b887B6a12925C",
|
||||
polygon_zkevm: "0xC5E56d6b40F3e3B5fbfa266bCd35C37426537c65",
|
||||
ronin: "0x2880aB155794e7179c9eE2e38200202908C17B43",
|
||||
scroll: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
shimmer: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
viction: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
wemix: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
zksync_era: "0xf087c864AEccFb6A2Bf1Af6A0382B0d0f6c5D834",
|
||||
// Testnets (Stable sources)
|
||||
arbitrum_sepolia: "0x4374e5a8b9C22271E9EB878A2AA31DE97DF15DAF",
|
||||
astar_zkevm_testnet: "0x8D254a21b3C86D32F7179855531CE99164721933",
|
||||
aurora_testnet: "0x74f09cb3c7e2A01865f424FD14F6dc9A14E3e94E",
|
||||
bnb_testnet: "0x5744Cbf430D99456a0A8771208b674F27f8EF0Fb",
|
||||
base_goerli: "0xEbe57e8045F2F230872523bbff7374986E45C486",
|
||||
boba_goerli: "0x8D254a21b3C86D32F7179855531CE99164721933",
|
||||
bttc_testnet: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
cant_testnet: "0x26DD80569a8B23768A1d80869Ed7339e07595E85",
|
||||
celo_alfajores: "0x74f09cb3c7e2A01865f424FD14F6dc9A14E3e94E",
|
||||
chiado: "0x98046Bd286715D3B0BC227Dd7a956b83D8978603",
|
||||
chiliz_testnet: "0x23f0e8FAeE7bbb405E7A7C3d60138FCfd43d7509",
|
||||
conflux_espace_testnet: "0xDd24F84d36BF92C65F92307595335bdFab5Bbd21",
|
||||
core_dao_testnet: "0x8D254a21b3C86D32F7179855531CE99164721933",
|
||||
cronos_testnet: "0x36825bf3Fbdf5a29E2d5148bfe7Dcf7B5639e320",
|
||||
eos_testnet: "0x0708325268dF9F66270F1401206434524814508b",
|
||||
evmos_testnet: "0x74f09cb3c7e2A01865f424FD14F6dc9A14E3e94E",
|
||||
fantom_testnet: "0x5744Cbf430D99456a0A8771208b674F27f8EF0Fb",
|
||||
fuji: "0x23f0e8FAeE7bbb405E7A7C3d60138FCfd43d7509",
|
||||
kcc_testnet: "0x74f09cb3c7e2A01865f424FD14F6dc9A14E3e94E",
|
||||
kava_testnet: "0xfA25E653b44586dBbe27eE9d252192F0e4956683",
|
||||
linea_goerli: "0xdF21D137Aadc95588205586636710ca2890538d5",
|
||||
manta_testnet: "0x41c9e39574F40Ad34c79f1C99B66A45eFB830d4c",
|
||||
mantle_testnet: "0xDd24F84d36BF92C65F92307595335bdFab5Bbd21",
|
||||
meter_testnet: "0x5a71C07a0588074443545eE0c08fb0375564c3E4",
|
||||
mode_testnet: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
mumbai: "0xFC6bd9F9f0c6481c6Af3A7Eb46b296A5B85ed379",
|
||||
neon_devnet: "0x0708325268dF9F66270F1401206434524814508b",
|
||||
optimism_goerli: "0xDd24F84d36BF92C65F92307595335bdFab5Bbd21",
|
||||
optimism_sepolia: "0x0708325268dF9F66270F1401206434524814508b",
|
||||
polygon_zkevm_testnet: "0xFf255f800044225f54Af4510332Aa3D67CC77635",
|
||||
saigon: "0xEbe57e8045F2F230872523bbff7374986E45C486",
|
||||
scroll_sepolia: "0x41c9e39574F40Ad34c79f1C99B66A45eFB830d4c",
|
||||
sepolia: "0xDd24F84d36BF92C65F92307595335bdFab5Bbd21",
|
||||
shimmer_testnet: "0x8D254a21b3C86D32F7179855531CE99164721933",
|
||||
viction_testnet: "0x5D289Ad1CE59fCC25b6892e7A303dfFf3a9f7167",
|
||||
wemix_testnet: "0x26DD80569a8B23768A1d80869Ed7339e07595E85",
|
||||
zetachain_testnet: "0x0708325268dF9F66270F1401206434524814508b",
|
||||
zksync_era_goerli: "0x8739d5024B5143278E2b15Bd9e7C26f6CEc658F1",
|
||||
zksync_era_sepolia: "0x056f829183Ec806A78c26C98961678c24faB71af",
|
||||
// Testnets (Beta sources)
|
||||
horizen_gobi_testnet: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
||||
};
|
|
@ -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"],
|
||||
"exclude": ["node_modules", "**/__tests__/*"]
|
||||
}
|
|
@ -80,7 +80,7 @@ async function main() {
|
|||
coinFlipContractAddress
|
||||
);
|
||||
|
||||
console.log(`Running coin flip prototcol.`);
|
||||
console.log(`Running coin flip protocol.`);
|
||||
|
||||
console.log("1. Generating user's random number...");
|
||||
const randomNumber = web3.utils.randomHex(32);
|
||||
|
|
Loading…
Reference in New Issue