tutorialcompleted

Use off-chain price feeds from SupraOracles in your IoTeX DePIN dApp

We'll be looking at how to build a "Lending Contract" where a user can leverage the monthly value, in $IOTX tokens, generated by their NFT (in this case a bike in a DePIN network) to borrow USD against it, using the SupraOracle price feed.

Post Header Image

Updated:


TIPS COLLECTED

...loading

SHARE

Off-chain price feeds in DePIN with SupraOracles and IoTeX


The full livestream tutorial can be found here: https://www.youtube.com/watch?v=x7NlClgGuSk
The post below is a full copy of the contracts used in the livestream. We'll essentially be looking at 3 contracts:

The IBikeSharingContract interface:


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

interface IBikeSharingContract {
// Provides the monthly income in IOTX for a given NFT
function getMonthlyIncome(uint256 nftId) external view returns (uint256);

}


The ISupraSValueFeed contract:


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

/**
* @title ISupraSValueFeed
* @notice Interface for interacting directly with Supra's sValueFeed contract.
* @dev Please refer to Supra's documentation: https://supraoracles.com/docs
*/
interface ISupraSValueFeed {

// Data structure to hold the pair data
struct dataWithoutHcc {
uint256 round;
uint256 decimals;
uint256 time;
uint256 price;
}

// Data structure to hold the pair data with History Consistency Check
struct dataWithHcc {
uint256 round;
uint256 decimals;
uint256 time;
uint256 price;
uint256 historyConsistent;
}

// Data structure to hold the derived pair data
struct derivedData{
int256 roundDifference;
int256 timeDifference;
uint256 derivedPrice;
uint256 decimals;
}

// Below functions enable you to retrieve different flavours of S-Value

// Function to fetch the data for a single data pair
function getSvalue(uint256 _pairIndex)
external
view
returns (dataWithoutHcc memory);

//Function to fetch the data for a multiple data pairs
function getSvalues(uint256[] memory _pairIndexes)
external
view
returns (dataWithoutHcc[] memory);

// Function to Fetch the Data for a single data pair with HCC
function getSvalueWithHCC(uint256 _pairIndex)
external
view
returns (dataWithHcc memory);

// Function to Fetch the Data for a multiple data pairs with HCC
function getSvaluesWithHCC(uint256[] memory _pairIndexes)
external
view
returns (dataWithHcc[] memory);

// Function to fetch the data for a derived data pair.
function getDerivedSvalue(uint256 _derivedPairId)
external
view
returns (derivedData memory);

// Function to fetch the timestamp(Last or Latest) of the data pair
// If you need to check the staleness of the data prior to requesting S-values
// use this function to check the last updated time stamp of the data pair.
function getTimestamp(uint256 _tradingPair)
external
view
returns (uint256);

}


The actual BikeShareLendingcontract


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "./IBikeSharingContract.sol";

import "./ISupraSValueFeed.sol";
//Price Feed Addresses: https://supraoracles.com/docs/price-feeds/decentralized/networks
//IOTEX mainnet: 0x1a83f5937979CdF9E60Af4C064Da367af2289eD3
//IOTEX testnet: 0x59f433fa29Fb2227b6E860956C654AfF7673Af10
//iotx_usdt pair index: 134

contract BikeShareLending {

IERC721 public bikeNFT;
IBikeSharingContract public bikeSharingContract;
ISupraSValueFeed internal sValueFeed;
ERC20 public usdtToken;

uint256 private constant IOTX_USD_PAIR_INDEX = 134; // iotx_usdt pair (https://supraoracles.com/docs/price-feeds/trading-pairs)

mapping(uint256 => address) public nftCollateralOwner;
mapping(address => uint256) public debtBalance;

constructor(address _bikeNFTAddress,
address _bikeSharingContractAddress,
address _supraOracleAddress,
address _usdtTokenAddress) {
bikeNFT = IERC721(_bikeNFTAddress);
bikeSharingContract = IBikeSharingContract(_bikeSharingContractAddress);
usdtToken = ERC20(_usdtTokenAddress);
sValueFeed = ISupraSValueFeed(_supraOracleAddress);
}

function depositNFT(uint256 nftId) external {
bikeNFT.transferFrom(msg.sender, address(this), nftId);
nftCollateralOwner[nftId] = msg.sender;
}

function borrowUSDT(uint256 nftId, uint256 amount) external {
require(nftCollateralOwner[nftId] == msg.sender, "Not NFT owner");
uint256 incomeIOTX = bikeSharingContract.getMonthlyIncome(nftId);
uint256 incomeUSD = incomeIOTX * getCurrentIOTXPrice() / (10 ** 18); // Convert IOTX income to USD
uint256 maxBorrow = incomeUSD / 4; // 25% of income
require(amount <= maxBorrow, "Exceeds maximum borrow amount");
usdtToken.transfer(msg.sender, amount);
debtBalance[msg.sender] += amount;
}

function getCurrentIOTXPrice() internal view returns (uint256) {
//Get the price data for iotx_usdt
ISupraSValueFeed.dataWithoutHcc memory data = sValueFeed.getSvalue(IOTX_USD_PAIR_INDEX);
//uint256 data.round
//uint256 data.decimals
//uint256 data.time
//uint256 data.price
return data.price;
}

// Additional functions like repayLoan, withdrawNFT, etc.
}


Docs

IoTeX Docs


IoTeX Developerslogo

[email protected]