From 3fe7bfc05d70433c4a0d2e71f300cb98b3696283 Mon Sep 17 00:00:00 2001 From: Ari <129996389+AriKimelman@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:21:15 +0100 Subject: [PATCH] Update redstone-core.mdx --- docs/get-started/models/redstone-core.mdx | 338 ++++++++-------------- 1 file changed, 126 insertions(+), 212 deletions(-) diff --git a/docs/get-started/models/redstone-core.mdx b/docs/get-started/models/redstone-core.mdx index 47333a50..3a4f774e 100644 --- a/docs/get-started/models/redstone-core.mdx +++ b/docs/get-started/models/redstone-core.mdx @@ -1,235 +1,111 @@ --- sidebar_position: 1 -sidebar_label: "⚙️ Core (on-demand feeds)" +sidebar_label: "Pull Model" --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -# ⚙️ Core Model - -## Fetching prices on-demand - -This is our basic operating model when the data is automatically appended to user transaction. - -:::tip In Prod - -Core model is the most mature way to use RedStone, battle tested in production, protecting >$100M TVL of [DeFi Protocols](https://defillama.com/oracles/RedStone) (not all listed yet) across multiple mainnets. The price feeds have been injected to more than [~50K transactions](https://dune.com/hatskier/redstone). - -::: - -## Installation - -Install [@redstone-finance/evm-connector](https://www.npmjs.com/package/@redstone-finance/evm-connector) from NPM registry - -### Hardhat - - - - -```bash - yarn add @redstone-finance/evm-connector -``` - - - - -```bash -npm install @redstone-finance/evm-connector -``` - - - - - -### Foundry - -Foundry installs dependencies using git submodules. Thus additional steps are needed to [install dependencies](https://book.getfoundry.sh/projects/dependencies). - -In foundry project: - -1. Install `@redstone-finance/evm-connector` - it will install current code from main branch - -```bash -forge install redstone-finance/redstone-oracles-monorepo -``` - -2. Install `@OpenZeppelin` contracts (dependency of `@redstone-finance/evm-connector`) - it will install current code from main branch - -```bash -forge install OpenZeppelin/openzeppelin-contracts@v4.9.5 -``` - -3. Add libraries to `remappings.txt` - -```bash +# Pull Model +This is our recommended model which provides data feeds to dApps only upon request, reducing the costs of putting data onto the blockchain. To learn more about how RedStone brings data on-chain, check out the [Data Formatting and Processing](https://docs.redstone.finance/docs/get-started/data-formatting-processing) section. +### Prerequisites Before You Begin: + +- **Knowledge of Smart Contracts:** Understanding how to implement and interact with smart contracts. +- **Familiarity with Hardhat or Foundry:** Knowing how to use these development environments for building and testing dApps. +- **OpenZeppelin Contracts:** Understanding and using OpenZeppelin's library. + +### Important Notes: +- **Solidity Version:** Ensure your smart contract uses Solidity version 0.8.4 or higher. If using an older version, refer to the manual payload method. +- **Testing Environment:** Remix is not supported for testing RedStone Oracles. +- **Upgradability:** Implement an upgradability mechanism (e.g., multisig or DAO) for your contracts to quickly replace data providers if needed. +- **Examples:** You can see examples of the `@redstone-finance/evm-connector` usage in our [dedicated repo with examples](https://github.com/redstone-finance/redstone-evm-examples). + + +# ****Step-by-Step Guide**** + +## 1. Install Prerequisites + +#### For Hardhat +1. To add the RedStone EVM connector package, type one of these commands: + - If you're using Yarn: + ```bash + yarn add @redstone-finance/evm-connector + ``` + - If you're using npm: + ```bash + npm install @redstone-finance/evm-connector + ``` + +#### For Foundry + +1. Open your terminal +2. Navigate to your Foundry project directory + ```bash + cd path/to/your/foundry/project + ``` + +3. Install the RedStone EVM connector + + ``` + forge install redstone-finance/redstone-oracles-monorepo + ``` + +4. Install the OpenZeppelin contracts, which the RedStone connector relies on. + + ``` + forge install OpenZeppelin/openzeppelin-contracts@v4.9.5 + ``` +5. Link these new libraries by adding their paths to a file called remappings.txt. + ```bash echo "@redstone-finance/evm-connector/dist/contracts/=lib/redstone-oracles-monorepo/packages/evm-connector/contracts/ @openzeppelin/contracts=lib/openzeppelin-contracts/contracts/" >> remappings.txt ``` -## Usage - -:::tip TLDR; -You need to do 2 things: - -1. [Adjust your smart contracts](#1-adjust-your-smart-contracts) to include the libraries responsible for data extraction and verification -2. [Adjust Javascript code of your dApp](#2-adjust-javascript-code-of-your-dapp) to inject the additional payload with data feeds (otherwise you will get smart contract errors). - - - -::: - -### 1. Adjust your smart contracts -:::caution Heads up -1. Our contracts require `solidity > 0.8.4`. If your code is written in an older version please use the [Manual Payload](#manual-payload). -2. If you work with 3rd party aggregators, make sure that they also support passing the additional payload. -3. Please don't use Remix to test RedStone oracles, as Remix does not support modifying transactions in the way that the evm-connector does -4. We strongly recommend having some upgradability mechanism for your contracts (it can be based on multisig or DAO). This way, you can quickly replace data providers in case of any issues. -::: - - -You need to apply a minimum change to the source code to enable smart contract to access data. Your contract needs to extend one of our [base contracts](https://github.com/redstone-finance/redstone-oracles-monorepo/tree/main/packages/evm-connector/contracts/data-services), depending on which data service are you going to use. - -
- List of base contracts with data services - - | Base Contract | Data service with the list of feeds | Status | - |----------------------------------------|------------------------------|-----------------| - | [MainDemoConsumerBase.sol](https://github.com/redstone-finance/redstone-oracles-monorepo/blob/main/packages/evm-connector/contracts/data-services/MainDemoConsumerBase.sol) | [redstone-main-demo](https://app.redstone.finance/#/app/data-services/redstone-main-demo) | Demo | - | [RapidDemoConsumerBase.sol](https://github.com/redstone-finance/redstone-oracles-monorepo/blob/main/packages/evm-connector/contracts/data-services/RapidDemoConsumerBase.sol) | [redstone-rapid-demo](https://app.redstone.finance/#/app/data-services/redstone-rapid-demo) | Demo | - | [StocksDemoConsumerBase.sol](https://github.com/redstone-finance/redstone-oracles-monorepo/blob/main/packages/evm-connector/contracts/data-services/StocksDemoConsumerBase.sol) | [redstone-stocks-demo](https://app.redstone.finance/#/app/data-services/redstone-stocks-demo) | Demo | - | [AvalancheDataServiceConsumerBase.sol](https://github.com/redstone-finance/redstone-oracles-monorepo/blob/main/packages/evm-connector/contracts/data-services/AvalancheDataServiceConsumerBase.sol) | [redstone-avalanche-prod](https://app.redstone.finance/#/app/data-services/redstone-avalanche-prod) | Production | - | [PrimaryProdDataServiceConsumerBase.sol](https://github.com/redstone-finance/redstone-oracles-monorepo/blob/main/packages/evm-connector/contracts/data-services/PrimaryProdDataServiceConsumerBase.sol) | [redstone-primary-prod](https://app.redstone.finance/#/app/data-services/redstone-primary-prod) | Production | - - - 💡 Note: Service with `Production` status have got multiple nodes deployed and are professionally monitored. -
+## 2. Adjust Your Smart Contracts +#### 1. Import RedStone Base Contract +Add this line at the top of your smart contract code. ```js import "@redstone-finance/evm-connector/contracts/data-services/MainDemoConsumerBase.sol"; - -contract YourContractName is MainDemoConsumerBase { - ... -} ``` -You should pass the data feed id converted to `bytes32`. - - - - -```js - uint256 ethPrice = getOracleNumericValueFromTxMsg(bytes32("ETH")); -``` - - - - -```js - bytes32[] memory dataFeedIds = new bytes32[](2); - dataFeedIds[0] = bytes32("ETH"); - dataFeedIds[1] = bytes32("BTC"); - uint256[] memory values = getOracleNumericValuesFromTxMsg(dataFeedIds); - uint256 ethPrice = values[0]; - uint256 btcPrice = values[1]; -``` - - - - - -For all the supported feeds we provide [UI with charts and historical data](https://app.redstone.finance) - -💡 Note: You can also override the following functions (do it at your own risk): - -- `isTimestampValid(uint256 receivedTimestamp) returns (bool)` - to enable custom logic of timestamp validation. You may specify a shorter delay to accept only the most recent price fees. However, on networks with longer block times you may extend this period to avoid rejecting too many transactions. - -- `aggregateValues(uint256[] memory values) returns (uint256)` - to enable custom logic of aggregating values from different providers (by default this function takes the median value). For example, you may request values from providers to be strictly equal while dealing with discrete numbers. - -- `getAuthorisedSignerIndex(address _signerAddress) returns (uint256)` - to whitelist additional signers or remove corrupted ones. - - -- `getUniqueSignersThreshold() returns (uint256)` - to modify number of required signers. The higher number means greater reliability but also higher gas costs. - -### 2. Adjust Javascript code of your dApp - -You should also update the code responsible for submitting transactions. If you're using [ethers.js](https://github.com/ethers-io/ethers.js/), we've prepared a dedicated library to make the transition seamless. - -#### Contract object wrapping - -First, you need to import the wrapper code to your project - - - +#### 2. Extend Your Contract +Make your contract use the new features by extending from MainDemoConsumerBase. ```js - const { WrapperBuilder } = require("@redstone-finance/evm-connector"); -``` - - - - -```js - import { WrapperBuilder } from "@redstone-finance/evm-connector"; -``` - - - -Then you can wrap your ethers contract pointing to the selected [RedStone data service id.](https://app.redstone.finance/#/app/data-services) You can (optionally) specify a number of unique signers, data feed identifiers, and URLs for the redstone cache nodes. - -```js -const yourEthersContract = new ethers.Contract(address, abi, provider); - -const wrappedContract = WrapperBuilder.wrap(contract).usingDataService( - { - dataFeeds: ["ETH", "BTC"], - }, -); +contract YourContractName is MainDemoConsumerBase { + // Your contract code goes here +} ``` +#### 3. Use Data Feeds +Inside your contract, you can now access data provided by RedStone. This code fetches the latest price of ETH and BTC. -Now you can access any of the contract's methods in exactly the same way as interacting with the ethers-js code: - +For a single price: ```js -wrappedContract.executeYourMethod(); +uint256 ethPrice = getOracleNumericValueFromTxMsg(bytes32("ETH")); ``` - -#### Testing - -##### Hardhat - -If you'd like to use the wrapper in a test context, we recommend using a mock wrapper so that you can easily override the oracle values to test different scenarios. To use the mock wrapper just use the `usingMockData(signedDataPackages)` function instead of the `usingDataService` function. - +For multiple prices: ```js -const { SimpleNumericMockWrapper } = require("@redstone-finance/evm-connector/dist/src/wrappers/SimpleMockNumericWrapper"); - -const wrappedContract = - WrapperBuilder.wrap(yourContract).usingSimpleNumericMock( - { - mockSignersCount: 10, - dataPoints: [ - {dataFeedId: "ETH", value: 1000} - ], - }, - ); - await wrappedContract.yourMethod(); +bytes32[] memory dataFeedIds = new bytes32[](2); +dataFeedIds[0] = bytes32("ETH"); +dataFeedIds[1] = bytes32("BTC"); +uint256[] memory values = getOracleNumericValuesFromTxMsg(dataFeedIds); +uint256 ethPrice = values[0]; +uint256 btcPrice = values[1]; ``` +For all the supported feeds we provide UI with charts and historical data. + +#### 4. About overriding the following functions (only if necessary - at your own risk) -You can see more examples of mocking data [here.](https://github.com/redstone-finance/redstone-oracles-monorepo/tree/main/packages/evm-connector/test/mock-wrapper) +```isTimestampValid(uint256 receivedTimestamp)``` returns (bool) - to enable custom logic of timestamp validation. You may specify a shorter delay to accept only the most recent price fees. However, on networks with longer block times you may extend this period to avoid rejecting too many transactions. -##### Foundry +```aggregateValues(uint256[] memory values)``` returns (uint256) - to enable custom logic of aggregating values from different providers (by default this function takes the median value). For example, you may request values from providers to be strictly equal while dealing with discrete numbers. -To use RedStone Oracles with Foundry in test context, we recommend using foundry `vm.ffi` function to generate mocked dataPackages. -We have prepared [repository](https://github.com/redstone-finance/minimal-foundry-repo) showing how we can integrate foundry with redstone. -- [consuming redstone payload in foundry contract](https://github.com/redstone-finance/minimal-foundry-repo/blob/main/test/Counter.t.sol) -- [generating mock redstone payload](https://github.com/redstone-finance/minimal-foundry-repo/blob/main/getRedstonePayload.js) +```getAuthorisedSignerIndex(address _signerAddress)``` returns (uint256) - to whitelist additional signers or remove corrupted ones. -## Manual payload -This approach is helpful if you need to pass the pricing data from one contract to another in your protocol. +```getUniqueSignersThreshold()``` returns (uint256) - to modify number of required signers. The higher number means greater reliability but also higher gas costs. -It's also a solution for a case, where your contracts are written in solidity in a version lower than `0.8.4` it could be problematic to extend from the `RedstoneConsumerBase` contract. -In that case we recomment to deploy a separate `Extractor` contract that will contain the verification logic: +#### 5. About a manual payload (if needed) +This approach is helpful if you need to pass the pricing data from one contract to another in your protocol. It's also a solution for cases where your contracts are written in Solidity in a version lower than 0.8.4, making it problematic to extend from the RedstoneConsumerBase contract. In such cases, we recommend deploying a separate Extractor contract that will contain the verification logic. ```js pragma solidity 0.8.4; @@ -242,17 +118,11 @@ contract RedstoneExtractor is RedstoneConsumerNumericMock { } } ``` - -and proxy the payload from your originating contract - ```js function getPriceFromRedstoneOracle(bytes32 feedId, bytes calldata redstonePayload) public view returns(uint256) { return redstoneExtractor.extractPrice(feedId, redstonePayload); } ``` - -The manual payload could be obtained using the following code on the client side: - ```js const redstonePayload = await (new DataServiceWrapper({ dataServiceId: "redstone-main-demo", @@ -262,7 +132,51 @@ const redstonePayload = await (new DataServiceWrapper({ // Interact with the contract (getting oracle value securely) const price = await yourContract.getPriceFromRedstoneOracle(redstonePayload); ``` +Working demo examples of the @redstone-finance/evm-connector usage can be found in our [dedicated repository with examples](https://github.com/redstone-finance/redstone-evm-examples). + + + +## 3. Adjust JavaScript Code of Your dApp + +#### 1. Import the Wrapper Code + +```js +const { WrapperBuilder } = require("@redstone-finance/evm-connector"); +// or using ES6 syntax +import { WrapperBuilder } from "@redstone-finance/evm-connector"; +``` + +#### 2. Wrap Ethers contract + +```js +const yourEthersContract = new ethers.Contract(address, abi, provider); + +const wrappedContract = WrapperBuilder.wrap(contract).usingDataService({ + dataFeeds ["ETH", "BTC"], +}); +``` + +#### 3. Use the Wrapped Contract -## Working demo +```js +wrappedContract.executeYourMethod(); +``` +## 4. Testing +For Hardhat +Mock Wrapper for Testing. +Use a mock wrapper to simulate different scenarios without using real data: +```js +const { SimpleNumericMockWrapper } = require("@redstone-finance/evm-connector/dist/src/wrappers/SimpleMockNumericWrapper"); + +const wrappedContract = WrapperBuilder.wrap(yourContract).usingSimpleNumericMock({ + mockSignersCount: 10, + dataPoints: [{ dataFeedId: "ETH", value: 1000 }], +}); + +await wrappedContract.yourMethod(); + +``` +For Foundry +Generate Mock Data: +Use Foundry's functions to create mock data packages for testing. Refer to the [foundry integration repository](https://github.com/redstone-finance/minimal-foundry-repo) for detailed examples. -You can see examples of the `@redstone-finance/evm-connector` usage in our [dedicated repo with examples](https://github.com/redstone-finance/redstone-evm-examples).