-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
### Includes - Updates UI to align with the new branding - Add Tellor guide
- Loading branch information
Showing
63 changed files
with
8,639 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 162 additions & 0 deletions
162
docs/building-on-lisk/using-oracle-data/redstone-pull.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
--- | ||
title: ...with Redstone (Pull) | ||
slug: /building-on-lisk/using-oracle-data/redstone-pull | ||
description: A guide on using Redstone Data Feeds to access real-world data such as asset prices, directly from your smart contracts on the Lisk testnet. | ||
keywords: [ | ||
Oracle | ||
Oracles, | ||
Redstone, | ||
price feeds, | ||
data feeds, | ||
smart contract, | ||
Lisk blockchain, | ||
Lisk network, | ||
Lisk testnet, | ||
Lisk test network, | ||
app development, | ||
dapp development, | ||
build a dapp on Lisk, | ||
build on Lisk, | ||
] | ||
--- | ||
|
||
# Accessing real-world data using the Redstone Oracle | ||
|
||
This page will explain how you can access oracle data using Redstone. | ||
|
||
RedStone is a data ecosystem that delivers frequently updated, reliable, and diverse data for your dApp and smart contracts deployed on Lisk. | ||
|
||
## How to pull oracle data from Redstone | ||
|
||
To create a smart contract that directly fetches the latest data from the Redstone oracle, follow this guide. | ||
|
||
This guide uses the [Redstone Pull model](https://docs.redstone.finance/docs/get-started/models/redstone-pull) to fetch the data. | ||
|
||
For an overview of the different modules that Redstone offers to receive oracle data, go to [Oracles > Redstone](../../lisk-tools/oracles#redstone). | ||
|
||
[Hardhat](https://hardhat.org/) is used in this guide to create the smart contract. | ||
In case you want to use Foundry, check out the [Redstone docs](https://docs.redstone.finance/docs/get-started/models/redstone-pull#foundry) for instructions. | ||
|
||
### Dependencies | ||
|
||
- ethers ^5.7.2 | ||
- hardhat ^2.14.0 | ||
|
||
### Install the evm connector | ||
Install the [@redstone-finance/evm-connector](https://www.npmjs.com/package/@redstone-finance/evm-connector) package. | ||
|
||
```sh | ||
npm install @redstone-finance/evm-connector | ||
``` | ||
|
||
### Import the evm connector | ||
|
||
```solidity | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.9; | ||
/** | ||
* Imports the EVM connector | ||
*/ | ||
import "@redstone-finance/evm-connector/contracts/data-services/RapidDemoConsumerBase.sol"; | ||
contract YourContract is RapidDemoConsumerBase { | ||
// ... | ||
} | ||
``` | ||
### Get oracle data | ||
|
||
Get the oracle data using the functions provided by the EVM connector. | ||
|
||
#### Get a single value | ||
|
||
To get a single price feed, use the function `getOracleNumericValueFromTxMsg()` and provide the data feed ID as a parameter. | ||
|
||
```solidity | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.9; | ||
/** | ||
* Imports the EVM connector | ||
*/ | ||
import "@redstone-finance/evm-connector/contracts/data-services/RapidDemoConsumerBase.sol"; | ||
contract YourContract is RapidDemoConsumerBase { | ||
// ... | ||
/** | ||
* Returns the latest price of ETH | ||
*/ | ||
function getLatestEthPrice() public view returns (uint256) { | ||
bytes32 dataFeedId = bytes32("ETH"); | ||
return getOracleNumericValueFromTxMsg(dataFeedId); | ||
} | ||
} | ||
``` | ||
|
||
#### Get multiple values | ||
|
||
To get data from multiple price feeds, use the function `getOracleNumericValuesFromTxMsg()` and provide the data feed ID array as a parameter. | ||
|
||
```solidity | ||
/** | ||
* Returns the latest prices of ETH and BTC | ||
*/ | ||
function getLatestEthBtcPrices() public view returns (uint256[] memory) { | ||
bytes32[] memory dataFeedIds = new bytes32[](2); | ||
dataFeedIds[0] = bytes32("ETH"); | ||
dataFeedIds[1] = bytes32("BTC"); | ||
uint256[] memory values = getOracleNumericValuesFromTxMsg(dataFeedIds); | ||
return values; | ||
} | ||
``` | ||
|
||
### Testing | ||
|
||
In order to test the EVM connector related functions in your contract, it is necessary to wrap the contract using the `WrapperBuilder` provided by the `@redstone-finance/evm-connector` package. | ||
|
||
```typescript title="test/YourContract.ts" | ||
import { expect } from "chai"; | ||
import { ethers } from "hardhat"; | ||
import { WrapperBuilder } from "@redstone-finance/evm-connector"; | ||
|
||
describe("YourContract", function () { | ||
describe("Redstone", function () { | ||
it("Get ETH price securely", async function () { | ||
const YourContract = await ethers.getContractFactory("YourContract"); | ||
const contract = await YourContract.deploy(); | ||
const wrappedContract = WrapperBuilder.wrap(contract).usingDataService({ | ||
dataFeeds: ["ETH"], | ||
}); | ||
|
||
// Interact with the contract (getting oracle value securely) | ||
const ethPriceFromContract = await wrappedContract.getLatestEthPrice(); | ||
console.log("Latest ETH price:"); | ||
console.log({ ethPriceFromContract }); | ||
}); | ||
}); | ||
}); | ||
``` | ||
|
||
Now run the test: | ||
|
||
```bash | ||
npx hardhat test | ||
``` | ||
|
||
This should output the latest ETH price in the console: | ||
|
||
``` title="Output" | ||
Latest ETH price: | ||
{ ethPriceFromContract: BigNumber { value: "250255087192" } } | ||
``` | ||
|
||
## Deploying on Lisk | ||
|
||
To deploy the smart contract on Lisk Sepolia or Lisk Mainnet, follow the guides | ||
|
||
- [Deploying a smart contract with Hardhat](../deploying-smart-contract/with-Hardhat), or | ||
- [Deploying a smart contract with Foundry](../deploying-smart-contract/with-Foundry) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
--- | ||
title: ...with Tellor | ||
slug: /building-on-lisk/using-oracle-data/tellor | ||
description: A guide on using Redstone Data Feeds to access real-world data such as asset prices, directly from your smart contracts on the Lisk testnet. | ||
keywords: [ | ||
Oracle | ||
Oracles, | ||
Redstone, | ||
price feeds, | ||
data feeds, | ||
smart contract, | ||
Lisk blockchain, | ||
Lisk network, | ||
Lisk testnet, | ||
Lisk test network, | ||
app development, | ||
dapp development, | ||
build a dapp on Lisk, | ||
build on Lisk, | ||
] | ||
--- | ||
|
||
# Using oracle data with Tellor | ||
[Tellor](https://tellor.io/) is an immutable decentralized oracle protocol where parties can request the value of an offchain data point (e.g. ETH/USD, LSK/USD) and reporters compete to add this value to an onchain databank. | ||
The inputs to this databank are secured by a network of staked reporters. | ||
|
||
Tellor utilizes crypto-economic incentive mechanisms, rewarding honest data submissions by reporters and punishing bad actors through the issuance of Tellor’s token, Tributes (TRB) and a dispute mechanism. | ||
|
||
This incentivizes an open, permissionless network of data reporting and data validation, ensuring that data can be provided by anyone and checked by everyone. | ||
|
||
## Installation | ||
The first thing you'll want to do is install the basic tools necessary for using Tellor as your oracle. | ||
|
||
To install [usingtellor](https://github.com/tellor-io/usingtellor), run one the following commands: | ||
|
||
- Hardhat: `npm install usingtellor` | ||
- Foundry: `forge install tellor-io/usingtellor` | ||
|
||
Once installed, this will allow your contracts to inherit the functions from the 'UsingTellor' contract. | ||
|
||
Great! Now that you've got the tools ready, let's go through a simple exercise where we retrieve the `eth/usd` and `lsk/usd` prices from Tellor. | ||
|
||
## Import | ||
|
||
```solidity | ||
pragma solidity >=0.8.0; | ||
import "usingtellor/contracts/UsingTellor.sol"; | ||
/** | ||
* Network: Lisk Mainnet | ||
* Address: 0x896419Ed2E0dC848a1f7d2814F4e5Df4b9B9bFcc | ||
*/ | ||
contract MyContract is UsingTellor { | ||
constructor(address payable _tellorOracle) UsingTellor(_tellorOracle) { | ||
} | ||
// ... | ||
} | ||
``` | ||
|
||
To import the UsingTellor contract into your Solidity file, pass the desired Tellor Oracle address as a parameter. | ||
For the Lisk Mainnet, the Tellor Oracle address is: [0x896419Ed2E0dC848a1f7d2814F4e5Df4b9B9bFcc](https://blockscout.lisk.com/address/0x896419Ed2E0dC848a1f7d2814F4e5Df4b9B9bFcc) | ||
|
||
## Reading data | ||
|
||
In the example below, we add two functions: | ||
|
||
- `getETHSpotPrice()` that reads the ETH/USD price feed and another function | ||
- `getLSKSpotPrice()` that reads the LSK/USD price feed from the Oracle | ||
|
||
```solidity | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.0; | ||
import { UsingTellor } from "usingtellor/contracts/UsingTellor.sol"; | ||
contract MyContract is UsingTellor { | ||
uint256 public ethLastStoredTimestamp; | ||
uint256 public ethLastStoredPrice; | ||
uint256 public lskLastStoredTimestamp; | ||
uint256 public lskLastStoredPrice; | ||
bytes32 public immutable ethQueryId; | ||
bytes32 public immutable lskQueryId; | ||
uint256 public constant DISPUTE_BUFFER = 20 minutes; | ||
uint256 public constant STALENESS_AGE = 12 hours; | ||
error StalePrice(uint256 price, uint256 timestamp); | ||
error NoValueRetrieved(uint256 timestamp); | ||
/** | ||
* @dev the constructor sets the Tellor address and the ETH and LSK queryIds | ||
* @param _tellorOracle is the address of the Tellor oracle | ||
*/ | ||
constructor (address payable _tellorOracle) UsingTellor(_tellorOracle) { | ||
// set the ETH queryId | ||
bytes memory _ethQueryData = abi.encode("SpotPrice", abi.encode("eth", "usd")); | ||
ethQueryId = keccak256(_ethQueryData); | ||
// set the LSK queryId | ||
bytes memory _lskQueryData = abi.encode("SpotPrice", abi.encode("lsk", "usd")); | ||
lskQueryId = keccak256(_lskQueryData); | ||
} | ||
/** | ||
* @dev Allows a user contract to read the ETH price from Tellor and perform some | ||
* best practice checks on the retrieved data | ||
* @return _value the ETH spot price from Tellor, with 18 decimal places | ||
* @return timestamp the value's timestamp | ||
*/ | ||
function getETHSpotPrice() | ||
public | ||
returns ( | ||
uint256 _value, | ||
uint256 timestamp | ||
) | ||
{ | ||
// retrieve the most recent 20+ minute old ETH price. | ||
// the buffer allows time for a bad value to be disputed | ||
(bytes memory _data, uint256 _timestamp) = _getDataBefore(ethQueryId, block.timestamp - DISPUTE_BUFFER); | ||
// check whether any value was retrieved | ||
if (_timestamp == 0 || _data.length == 0) revert NoValueRetrieved(_timestamp); | ||
// decode the value from bytes to uint256 | ||
_value = abi.decode(_data, (uint256)); | ||
// prevent a back-in-time dispute attack by caching the most recent value and timestamp. | ||
// this stops an attacker from disputing tellor values to manupulate which price is used | ||
// by your protocol | ||
if (_timestamp > ethLastStoredTimestamp) { | ||
// if the new value is newer than the last stored value, update the cache | ||
ethLastStoredTimestamp = _timestamp; | ||
ethLastStoredPrice = _value; | ||
} else { | ||
// if the new value is older than the last stored value, use the cached value | ||
_value = ethLastStoredPrice; | ||
_timestamp = ethLastStoredTimestamp; | ||
} | ||
// check whether value is too old | ||
if (block.timestamp - _timestamp > STALENESS_AGE) revert StalePrice(_value, _timestamp); | ||
// return the value and timestamp | ||
return (_value, _timestamp); | ||
} | ||
/** | ||
* @dev Allows a user contract to read the LSK price from Tellor and perform some | ||
* best practice checks on the retrieved data | ||
* @return _value the LSK spot price from Tellor, with 18 decimal places | ||
* @return timestamp the value's timestamp | ||
*/ | ||
function getLSKSpotPrice() | ||
public | ||
returns ( | ||
uint256 _value, | ||
uint256 timestamp | ||
) | ||
{ | ||
(bytes memory _data, uint256 _timestamp) = _getDataBefore(lskQueryId, block.timestamp - DISPUTE_BUFFER); | ||
if (_timestamp == 0 || _data.length == 0) revert NoValueRetrieved(_timestamp); | ||
_value = abi.decode(_data, (uint256)); | ||
if (_timestamp > lskLastStoredTimestamp) { | ||
lskLastStoredTimestamp = _timestamp; | ||
lskLastStoredPrice = _value; | ||
} else { | ||
_value = lskLastStoredPrice; | ||
_timestamp = lskLastStoredTimestamp; | ||
} | ||
if (block.timestamp - _timestamp > STALENESS_AGE) revert StalePrice(_value, _timestamp); | ||
return (_value, _timestamp); | ||
} | ||
} | ||
``` | ||
|
||
You can adapt this contract to your needs. | ||
The example utilizes some best practices[^1] for using Tellor by implementing a dispute time buffer and a data staleness check. | ||
In addition, it also seeks to mitigate back-in-time dispute attacks by caching the most recent value and timestamp. | ||
|
||
[^1]: Based on examples in [Tellor's best practices repository](https://github.com/tellor-io/best-practices-user/tree/main) | ||
|
||
:::tip | ||
For a general overview of best practices using Tellor, go to the [User checklists](https://docs.tellor.io/tellor/getting-data/user-checklists) in the Tellor docs. | ||
::: | ||
|
||
## Deploying on Lisk | ||
|
||
To deploy the smart contract on Lisk Sepolia or Lisk Mainnet, follow the guides | ||
|
||
- [Deploying a smart contract with Hardhat](../deploying-smart-contract/with-Hardhat), or | ||
- [Deploying a smart contract with Foundry](../deploying-smart-contract/with-Foundry) | ||
|
||
## Further resources | ||
|
||
- For a more robust implementation of the Tellor oracle, check out the full list of available functions [here](https://github.com/tellor-io/usingtellor/blob/master/README.md). | ||
- Have a specific Data Feed Request? [Fill out this form](https://github.com/tellor-io/dataSpecs/issues/new?assignees=&labels=&template=new_query_type.yaml&title=%5BNew+Data+Request+Form%5D%3A+). | ||
- Still have question? Reach out to the Tellor team on Discord [here](https://discord.gg/tellor). |
Oops, something went wrong.