Skip to main content

Price feeds

Pyth

Pyth offers 400+ pull-based price feeds for Etherlink. Learn more about integrating Pyth with their documentation on How to Use Real-Time Price Data.

This example contract accepts price update data from Pyth and uses it to provide the price of one XTZ in USD:

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

import "@pythnetwork/pyth-sdk-solidity/IPyth.sol";

contract PythSimple {
// Pyth oracle data
IPyth pyth;
// Price feed ID from https://legacy.pyth.network/developers/price-feed-ids
bytes32 xtzUsdPriceId;

constructor(address _pyth, bytes32 _priceId) {
pyth = IPyth(_pyth);
xtzUsdPriceId = _priceId;
}

function getPriceId() view external returns (bytes32 _priceId) {
return (xtzUsdPriceId);
}

function getPrice() view external returns (uint256 _price){
PythStructs.Price memory price_ = pyth.getPriceUnsafe(xtzUsdPriceId);
return uint256(int256(price_.price));
}
}

To deploy this contract you need the address of the Pyth on-chain application on Etherlink (0x2880aB155794e7179c9eE2e38200202908C17B43 on Mainnet and Shadownet Testnet) and the ID of the XTZ/USD price feed (0x0affd4b8ad136a21d79bc82450a325ee12ff55a235abc242666e423b8bcffd03 as listed on the Pyth Price feed IDs).

Here is an example JavaScript application that uses the viem SDK to call the contract on Etherlink:

import { createWalletClient, http, getContract } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { etherlinkShadownetTestnet } from "viem/chains";

const PythContractABI = [
{
"type": "constructor",
"inputs": [
{
"name": "_pyth",
"type": "address",
"internalType": "address"
},
{
"name": "_priceId",
"type": "bytes32",
"internalType": "bytes32"
}
],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "getPrice",
"inputs": [],
"outputs": [
{
"name": "_price",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "getPriceId",
"inputs": [],
"outputs": [
{
"name": "_priceId",
"type": "bytes32",
"internalType": "bytes32"
}
],
"stateMutability": "view"
}
];

// Address of deployed contract
const CONTRACT_ADDRESS = "<DEPLOYMENT_ADDRESS>";

// My account based on private key
const myAccount = privateKeyToAccount(`<PRIVATE_KEY>`);

// Viem objects that allow programs to call the chain
const walletClient = createWalletClient({
account: myAccount,
chain: etherlinkShadownetTestnet,
transport: http(),
});
const contract = getContract({
address: CONTRACT_ADDRESS,
abi: PythContractABI,
client: walletClient,
});

const callContract = async () => {

const price = await contract.read.getPrice();
console.log(price);
// 52425196
console.log("1 XTZ =", parseInt(price) / 100000000, "USD");
// 1 XTZ = 0.52425196 USD

}

callContract();

Pyth also provides prices on Shadownet Testnet but the price does not change.

RedStone

RedStone offers push-based price feeds for Etherlink. Get started with their docs to learn more.

The example in etherlinkcom/infra-instruments includes a contract that retrieves pricing data from RedStone for multiple assets.

This example contract accepts price update data from RedStone and uses it to provide the price of one XTZ in USD:

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

// Chainlink aggregator interface
interface AggregatorV3Interface {
function decimals() external view returns (uint8);

function description() external view returns (string memory);

function version() external view returns (uint256);

function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}

contract RedStoneSimple {
address monitorAsset;

constructor(address _monitorAsset) {
monitorAsset = _monitorAsset;
}

function getAsset() view external returns (address _monitorAsset) {
return (monitorAsset);
}

function getPrice() view external returns (uint256 _price){
AggregatorV3Interface oracle_ = AggregatorV3Interface(monitorAsset);
(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) = oracle_.latestRoundData();
return uint256(answer);
}

function decimals() view external returns (uint256 _decimals) {
AggregatorV3Interface oracle_ = AggregatorV3Interface(monitorAsset);
return oracle_.decimals();
}
}

To deploy this contract you need the address of the RedStone contract that provides the XTZ/USD price feed:

  • 0xe92c00BC72dD12e26E61212c04E8D93aa09624F2 on Etherlink Mainnet
  • 0xb9D0073aCb296719C26a8BF156e4b599174fe1d5 on Etherlink Shadownet Testnet

Similarly, you can get the price of the URANIUM token in USD with these addresses:

  • 0xb81131B6368b3F0a83af09dB4E39Ac23DA96C2Db on Etherlink Mainnet
  • 0xED2B1ca5D7E246f615c2291De309643D41FeC97e on Etherlink Shadownet Testnet

For more price feed information, see the RedStone documentation.

Here is an example JavaScript application that uses the viem SDK to call the contract on Etherlink:

import { createWalletClient, http, getContract } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { etherlinkShadownetTestnet } from "viem/chains";

const RedStoneContractABI = [
{
"type": "constructor",
"inputs": [
{
"name": "_monitorAsset",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "decimals",
"inputs": [],
"outputs": [
{
"name": "_decimals",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "getAsset",
"inputs": [],
"outputs": [
{
"name": "_monitorAsset",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "getPrice",
"inputs": [],
"outputs": [
{
"name": "_price",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
}
];

// Address of deployed contract
const CONTRACT_ADDRESS = "<DEPLOYMENT_ADDRESS>";

// My account based on private key
const myAccount = privateKeyToAccount(`<PRIVATE_KEY>`);

// Viem objects that allow programs to call the chain
const walletClient = createWalletClient({
account: myAccount,
chain: etherlinkShadownetTestnet,
transport: http(),
});
const contract = getContract({
address: CONTRACT_ADDRESS,
abi: RedStoneContractABI,
client: walletClient,
});

const callContract = async () => {

const price = await contract.read.getPrice();
const decimals = await contract.read.decimals();
console.log(price);
// 52425196
console.log("1 XTZ =", parseInt(price) / (10 ** Number(decimals)), "USD");
// 1 XTZ = 0.52425196 USD

}

callContract();

Acelon

Acelon provides a price feed for the price of stXTZ tokens, part of a staking pool on Tezos layer 1.

This example contract accepts price update data from Acelon and uses it to provide the price of one STXTZ in XTZ:

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

// Chainlink aggregator interface
interface AggregatorV3Interface {
function decimals() external view returns (uint8);

function description() external view returns (string memory);

function version() external view returns (uint256);

function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}

contract AcurastSimple {
address monitorAsset;

constructor(address _monitorAsset) {
monitorAsset = _monitorAsset;
}

function getAsset() view external returns (address _monitorAsset) {
return (monitorAsset);
}

function getPrice() view external returns (uint256 _price){
AggregatorV3Interface oracle_ = AggregatorV3Interface(monitorAsset);
(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) = oracle_.latestRoundData();
return uint256(answer);
}

function decimals() view external returns (uint256 _decimals) {
AggregatorV3Interface oracle_ = AggregatorV3Interface(monitorAsset);
return oracle_.decimals();
}
}

To deploy this contract you need the address of the Acelon proxy on Etherlink (0x4Bf5C46Ee59a1110c2a242715f9c3b548A14ee02 on Mainnet). Acelon is not available on Etherlink testnets.

Here is an example JavaScript application that uses the viem SDK to get the price of stXTZ on Etherlink:

import { createWalletClient, http, getContract } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { etherlink } from "viem/chains";

// ABI of Acelon contract, abbreviated for this example
const abbreviatedAcelonABI = [
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "latestRoundData",
"outputs": [
{
"internalType": "uint80",
"name": "roundId",
"type": "uint80"
},
{
"internalType": "int256",
"name": "answer",
"type": "int256"
},
{
"internalType": "uint256",
"name": "startedAt",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "updatedAt",
"type": "uint256"
},
{
"internalType": "uint80",
"name": "answeredInRound",
"type": "uint80"
}
],
"stateMutability": "view",
"type": "function"
},
];

// stXTZ oracle on Etherlink Mainnet
const CONTRACT_ADDRESS = "0x4Bf5C46Ee59a1110c2a242715f9c3b548A14ee02";

// My account based on private key
const myAccount = privateKeyToAccount(`<PRIVATE_KEY>`);

// Viem objects that allow programs to call the chain
const walletClient = createWalletClient({
account: myAccount,
chain: etherlink,
transport: http(),
});
const contract = getContract({
address: CONTRACT_ADDRESS,
abi: abbreviatedAcelonABI,
client: walletClient,
});

const callContract = async () => {

// Get stxtz price
const decimals = await contract.read.decimals();
console.log("Decimals:", decimals);
const latestRoundData = await contract.read.latestRoundData();
const [roundId, answer, startedAt, updatedAt, answeredInRound] = latestRoundData;
console.log(answer);
console.log("1 STXTZ =", parseInt(answer) / (10 ** Number(decimals)), "XTZ");

}

callContract();

You can also use the NPM package @acelon/acelon-sdk for the same purpose.

arrow icon

Prev

Node providers

Next

arrow icon
Verifiable random functions
outline iconPage Outline