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.
Off-chain price feeds in DePIN with SupraOracles and IoTeX
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: MITpragma 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 BikeShareLending
contract
// SPDX-License-Identifier: MITpragma 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.}