September 4, 2023

Full guide about redstone-api

Note⚠

The data below is the README.md file from the official RedStone Github. This is followed by my personal review of the __tests__ file for informative purposes only.


Redstone API

In this article, I will talk about Redstone API, which is a JavaScript library for fetching trusted token price data from the Redstone data ecosystem. The Redstone data ecosystem is a decentralized network of oracles that provide trusted data on the prices of various tokens. The Redstone API is secured on Arweave, a decentralized storage network, and is protected by a pledge of oracles.

The Redstone API is used by a variety of applications including DeFi platforms, trading bots, and price aggregators. It provides a reliable and secure way to access trusted token pricing data.

Here are some of the key features of the Redstone API:

It is secured on Arweave, a decentralized storage network.
It is secured by oracle provisioning.
It supports a variety of tokens, including ERC-20, ERC-721, and BEP-20.
It provides real-time price data.
It is easy to use.
If you are looking for a reliable and secure way to access trusted token pricing data, Redstone API is a good option.



Redstone API is a Javascript library for fetching trusted token pricing data from Redstone data ecosystem.

It is a Javascript wrapper for Redstone HTTP Api.

🚀 Demo

Try it directly in CodeSandbox: demo link

✅ Why Redstone API

✓ Secure

Redstone pricing data is secured on Arweave and protected by the provider's collateral. Learn more

✓ Easy to use

You don't need any API keys. Just install the npm package and add a single line of code. Quick start

✓ 100+ tokens

We support BTC, ETH, AR, EUR, and many other crypto and fiat currencies. All supported tokens

✓ TypeScript Support

Redstone API is fully written in Typescript and then compiled to JavaScript. Source code

📖 Documentation

This readme should provide you with all the information you need to start using redstone api. If you want to see the full documentation, visit api.docs.redstone.finance

📦 Installation

Using npm

npm install redstone-api

Using yarn

yarn add redstone-api

🤖 Usage

Importing

// Using Node.js `require()`
const redstone = require('redstone-api');

// Using ES6 imports
import redstone from 'redstone-api';

Get the latest price for a single token

const price = await redstone.getPrice("AR");

console.log(price.value); // latest price value for AR token (in USD)
console.log(price.timestamp); // the exact timestamp of the price

💡 Note: All the prices are denominated in USD. You can fetch price data for BTC, ETH, AR, EUR and any other of 100+ supported tokens.

Available symbols

You can use a symbols object to explore all available symbols right in the code.

import redstone from 'redstone-api';

const price = await redstone.getPrice("AR");

Price data format🔽

{
  value: 123.23, // Number: Price value in USD
  timestamp: 1617146511173, // Number: Timestamp (ms) for price
  provider: "I-5rWUehEv-MjdK9gFw09RxfSLQX9DIHxG614Wf8qo0", // String: Provider arweave address
  permawebTx: "V8FUU0BG4kVOJwKWHzgkn1aEFm-eanhqqEXfPFY7pmI", // String: Arweave transaction id
  source: {"coingecko": 123,"sushiswap": 123.23,"uniswap": 123.35}, // Object: Prices from different sources
}

Fetch price using promises🔽

// As async/await is only a syntactic sugar on Javascript
// Promises you can use them in a "standard" way
const price = redstone.getPrice("AR").then((price) => {
  console.log(price.value); // latest price value for AR token
});

Get the latest prices for several tokens

To fetch prices for several tokens use the getPrice method and pass an array with any subset of supported tokens.

const prices = await redstone.getPrice(["BTC", "ETH", "AR", "EUR"]);

console.log(prices); // Example output below
/*
{
  "BTC": {
    value: 58953.39,
    timestamp: 1617152802779,
    ...
  },
  "ETH": {
    value: 1856.75,
    timestamp: 1617152802779,
    ...
  },
  ...
}
*/


console.log(prices["BTC"].value); // latest price value for BTC
console.log(prices["ETH"].value); // latest price value for ETH
console.log(prices["AR"].value); // latest price value for AR

Get prices for all available tokens

To fetch the latest prices for all available tokens use the getAllPrices method.

const prices = await redstone.getAllPrices();

console.log(prices); // Example output below
/*
{
  "BTC": {...},
  "ETH": {...},
  ...
}
*/

console.log(prices["AR"].value); // latest price value for AR
console.log(prices["EUR"].value); // latest price value for EUR

Get the historical price for a single token

To get the historical price use the getHistoricalPrice method.

const price = await redstone.getHistoricalPrice("AR", {
  date: "2021-03-30T12:35:09", // Any convertable to date type
});

console.log(price.value); // AR price for specific time

💡 Note: date argument must be convertable to Date type. You may pass date (e.g. new Date(2021-04-01)), timestamp (e.g. 1617709771289), or just string (e.g. 2021-04-01 or 2021-04-01T12:30:58).


Get the historical price for several tokens

To fetch the historical price for several tokens pass an array of symbols to getHistoricalPrice method.

const symbols = ["AR", "BTC", "UNI", "ETH", "EUR"];
const prices = await redstone.getHistoricalPrice(symbols, {
  date: "2021-03-30T12:35:09",
});

console.log(prices["BTC"].value); // BTC price for specific time

Get the historical prices in a time range

To fetch the historical prices in a time range specify token symbol as the first argument of the getHistoricalPrice method, and startDate, endDate and interval as fields of the second argument.

💡 Note: currently Redstone API supports fetching historical prices in a time range only for a single token.

const prices = await redstone.getHistoricalPrice("AR", {
  startDate: "2021-03-29T12:35:09",
  endDate: "2021-03-30T12:35:09",
  interval: 3600 * 1000, // 1 hour
});

console.log(prices); // Example output below
/*
[
  {
    value: 28.8,
    timestamp: 1617016995624,
    ...
  },
  {
    value: 28.59,
    timestamp: 1617014111705,
    ...
  },
  ...
]
*/

💡 Note: startDate and endDate argument must be convertable to Date type.

Get prices with pagination

To fetch prices with pagination specify token symbol as the first argument of the getHistoricalPrice method, and offset with limit as properties of the second argument.

💡 Note: pagination is supported only for a single token.

const prices = await redstone.getHistoricalPrice("AR", {
  offset: 1000,
  limit: 100,
});

Verify signature

All prices saved in Redstone have a signature, thanks to which you always can verify if the price data has been submitted by the trusted provider.

To do so you can set verifySignature option to true in getPrice, getHistoricalPrice or getAllPrices methods. If signature is invalid - error will be thrown.

const price = await redstone.getPrice("AR", {
  verifySignature: true,
});
console.log(price.value);

Fluent Interface

Redstone implements a fluent interface to simplify query creation thanks to a human readable syntax. Learn more

Using a custom cache api url

Option 1. Using a setCacheApiUrl method

redstone.setCacheApiUrl("http://localhost:9000/prices");
redstone.getPrice("AR").then(console.log);

Option 2. Initialising a new redstone api instance with a cacheApiUrl param

const redstoneApi = new redstone.Api({
  cacheApiUrl: "http://localhost:9000/prices",
});
redstoneApi.getPrice("AR").then(console.log);

💡 Note: To use a custom cache api url with the redstone fluent interface you should pass a cacheApiUrl as an argument of the exec method each time you make a query.

redstone.query().symbol("AR").latest().exec({
  cacheApiUrl: "http://localhost:9000/prices",
}).then(console.log);

Get prices from Arweave

By default, Redstone API fetches data from the Redstone cache layer. It works way faster than fetching directly from Arweave Blockchain. Even so, thanks to signature verification prices data is still trusted and secure.

We strongly recommend using the default fetching mechanism which leverages cache to speed up queries. But if you want to fetch data directly from Arweave you can do it by initialising a new Api client and setting useCache option to false.

const redstoneArweaveClient = new redstone.Api({ useCache: false });

const price = await redstoneArweaveClient.getPrice("AR");

console.log(price.value); // AR price value fetched directly from Arweave

🚀 Examples

💬 Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

📜 License

This software is licensed under the MIT © Redstone

Contents of redstone-api

  • __tests__ folder contains the unit tests for the project.
  • docs folder contains the documentation for the project.
  • examples folder contains example code for using the project.
  • src folder contains the source code for the project.
  • .gitignore file tells Git which files to ignore when tracking changes to the repository.
  • README.md file is the project README, which provides an overview of the project.
  • jestconfig.json file configures Jest, a JavaScript testing framework.
  • package.json file lists the dependencies for the project.
  • tsconfig.json file configures TypeScript, a programming language for JavaScript.
  • tslint.json file configures TSLint, a linter for TypeScript.
  • yarn.lock file tracks the exact versions of the dependencies for the project.


redstone-api/__tests__/arweave-signing.test.ts

The first thing the code does is import the ArweaveMultihost library. This library provides a way to interact with the Arweave blockchain.

The next part of the code defines a test case called shouldSignAndVerifySignature. This test case first generates a pair of cryptographic keys using the generate() method from the wallets module. The public key is then used to sign a string of data using the sign() method from the crypto module. The signature is then verified using the verify() method from the crypto module. The test case asserts that the signature is valid.

The next test case, shouldGetAddressFromOwner, also generates a pair of cryptographic keys. It then uses the jwkToAddress() method to convert the JSON Web Key (JWK) to an Arweave address. The ownerToAddress() method is then used to get the Arweave address from the public key. The test case asserts that the two addresses are the same.

In summary, the code in arweave-signing.test.ts tests the ability to sign and verify signatures on the Arweave blockchain. It also tests the ability to get the Arweave address from a public key.

Here are some additional details about the code:

  • The ArweaveMultihost library uses the Arweave API to interact with the blockchain. The API is a RESTful API that provides a way to read, write, and manage data on the blockchain.
  • The wallets module provides methods for generating, managing, and using cryptographic keys on Arweave.
  • The crypto module provides methods for signing and verifying signatures on Arweave.

redstone-api/__tests__/fluent-interface.test.ts

The code in fluent-interface.test.ts tests the fluent interface of the redstone API. The fluent interface allows you to chain together methods to specify the data you want to fetch.

The first test case, shouldGetARPrice, fetches the latest price of AR. It does this by calling the query() method, specifying the symbol AR and the latest() method. The exec() method executes the request and returns the price.

The second test case, shouldGetAAPLPriceWithRedstoneStocksProvider, fetches the latest price of AAPL using the redstone-stocks provider. It does this by calling the query() method, specifying the symbol AAPL, the latest() method, and the provider option.

The third test case, shouldGetASingleHistoricalARPrice, fetches a single historical price of AR. It does this by calling the query() method, specifying the symbol AR, the atDate() method, and the provider option.

The fourth test case, shouldGetHistoricalARPriceForTheLast12Hours, fetches the historical prices of AR for the last 12 hours. It does this by calling the query() method, specifying the symbol AR, the forLastHours() method, and the exec() method.

The fifth test case, shouldGetSingleHistoricalARPriceForThe24HoursAgo, fetches a single historical price of AR for the 24 hours ago. It does this by calling the query() method, specifying the symbol AR, the hoursAgo() method, and the exec() method.

The sixth test case, shouldGetHistoricalARPriceForLast7Days, fetches the historical prices of AR for the last 7 days. It does this by calling the query() method, specifying the symbol AR, the forLastDays() method, and the exec() method.

The seventh test case, shouldGetHistoricalARPriceForTheLast1Day, fetches the historical prices of AR for the last 1 day. It does this by calling the query() method, specifying the symbol AR, the forLastDays() method, and the exec() method.

The eighth test case, shouldGetARPriceInTimeRange, fetches the prices of AR in a specific time range. It does this by calling the query() method, specifying the symbol AR, the fromDate() method, the toDate() method, and the exec() method.

The ninth test case, shouldGetLatestPricesForARETHAndBTC, fetches the latest prices for AR, ETH, and BTC. It does this by calling the query() method, specifying the symbols ["AR", "ETH", "BTC"], the latest() method, and the exec() method.

The tenth test case, shouldGetTheHistoricalPriceForARETHAndBTC, fetches the historical prices for AR, ETH, and BTC for a specific date. It does this by calling the query() method, specifying the symbols ["AR", "ETH", "BTC"], the atDate() method, and the exec() method.

The eleventh test case, shouldGetTheLatestPricesForAllSymbols, fetches the latest prices for all symbols. It does this by calling the query() method, specifying the allSymbols() method, the latest() method, and the exec() method.

These are just a few examples of how the fluent interface can be used to fetch data from the RedStone Oracle API. The API also supports a number of other methods, such as filtering, sorting, and pagination.

redstone-api/__tests__/get-all-prices.test.ts

The code in get-all-prices.test.ts tests the getAllPrices() method of the redstone API. The getAllPrices() method fetches the latest prices for all symbols.

The first test case, shouldGetAllPrices, fetches all prices and asserts that the prices are for BTC, ETH, and AR. It also asserts that the prices are not older than 150 seconds.

The second test case, shouldGetAllPricesAndVerifyTheirSignatures, fetches all prices and verifies their signatures. This is done by setting the verifySignature option to true.

The third test case, shouldNotHaveTechnicalProps, fetches all prices and asserts that they do not have any technical properties. Technical properties are properties that are used by the RedStone Oracle API, but are not relevant to users.

These are just a few examples of how the getAllPrices() method can be used. The method also supports a number of other options, such as specifying the providers to use and the time range to fetch prices for.

redstone-api/__tests__/get-historical-price.test.ts

The code in get-historical-price.test.ts tests the getHistoricalPrice() method of the redstone API. The getHistoricalPrice() method fetches the historical price of a symbol for a given date.

The first test case, shouldGetARPriceFor2021-04-17, fetches the historical price of AR for 2021-04-17. It asserts that the price is 25.923827794046517 USD.

The second test case, shouldGetETHPriceFor2021-04-17, fetches the historical price of ETH for 2021-04-17. It asserts that the price is 2421.882615498678 USD.

The third test case, shouldGetETHPriceFor2021-04-17AndVerifySignature, fetches the historical price of ETH for 2021-04-17 and verifies the signature.

The fourth test case, shouldGetARBTCAndETHPriceFor2021-04-17, fetches the historical prices of AR, BTC, and ETH for 2021-04-17. It asserts that the prices are greater than 0.1 USD, 100 USD, and 1000 USD, respectively.

The fifth test case, shouldGetARPricesInATimeRange, fetches the historical prices of AR in the time range 2021-06-17 to 2021-06-18. It asserts that the number of prices is 144.

The sixth test case, shouldGetARPricesWithHourlyInterval, fetches the historical prices of AR with an hourly interval. It asserts that the number of prices is greater than or equal to 48 and less than or equal to 50.

The seventh test case, shouldGetARPricesWithPaging, fetches the historical prices of AR with paging. It asserts that the number of prices is 100.

The eighth test case, shouldNotFoundARPriceFor2019-01-01, tries to fetch the historical price of AR for 2019-01-01. It asserts that an error is thrown with the message Price not found for symbol: AR.

These are just a few examples of how the getHistoricalPrice() method can be used. The method also supports a number of other options, such as specifying the providers to use and the time range to fetch prices for.

redstone-api/__tests__/get-price.test.ts

This file contains unit tests for the getPrice() method of the redstone API. The getPrice() method fetches the latest price of a symbol.

The test cases in the file check for the following:

  • The method can fetch the latest price of AR.
  • The method can fetch the latest price of ETH.
  • The method does not have technical properties.
  • The method can fetch the latest prices for AR, ETH, and BTC.
  • The method can fetch the latest price of AAPL without explicitly setting the provider.
  • The method can fetch the latest price of LINK without explicitly setting the provider.
  • The method does not have technical properties.
  • The method can fetch the latest prices for AR, ETH, BNB, and BTC and verify the signatures.
  • The method can verify the signature for the latest ETH price.

The tests are well-written and cover all the possible scenarios. They are also concise and easy to read.

This is a breakdown of the code:

import redstone from "../src/index";
import config from "../src/config";

const MAX_TIME_DIFF = 90000; // 90s

const shouldNotHaveTechProps = (price: any) => {
  const technicalProps = ["signature", "version", "providerPublicKey"];
  for (const prop of technicalProps) {
    expect(price).not.toHaveProperty(prop);
  }
};

This code imports the redstone and config modules. The redstone module provides the API for fetching prices. The config module provides the configuration for the API.

The MAX_TIME_DIFF constant defines the maximum difference between the current time and the timestamp of a price before it is considered stale.

The shouldNotHaveTechProps() function checks if a price object does not have any technical properties. Technical properties are properties that are used to verify the authenticity of a price.

describe("Test getPrice method", () => {
  test("Should get AR price", async () => {
    const symbol = "AR";
    const price: any = await redstone.getPrice(symbol);

    expect(price).toBeDefined();
    expect(price.symbol).toBe(symbol);
    expect(price.provider).toBe(config.providers["redstone-rapid"].address);
    expect(price.value).toBeGreaterThan(0.1);
    expect(Date.now() - price.timestamp).toBeLessThan(MAX_TIME_DIFF);
  });

This test case checks if the getPrice() method can fetch the latest price of AR. The test case first creates a price object for AR. Then, it calls the getPrice() method and passes the symbol AR as an argument. Finally, the test case asserts that the price object returned by the getPrice() method has the expected properties.

The other test cases in the file are similar. They check if the getPrice() method can fetch the latest prices of ETH, AAPL, LINK, and other symbols. They also check if the getPrice() method can verify the signatures of prices.


Conclusion

As you have already realized, the tests/ folder contains unit tests for the Redstone API. Unit tests are small tests that test a single unit of code, such as a function or class. They are an important part of software development because they make sure that the code works correctly.

The unit tests in the tests/ folder are written in JavaScript and use the Jest framework. Jest is a popular JavaScript testing framework that makes it easy to write and execute unit tests.

Unit tests in the tests/ folder test the functionality of the Redstone API by making requests to the API and checking the results. For example, there is a unit test that tests the functionality of the getPrice() function. This function is used to get the current price of a token. The unit test executes a request to the API to get the price of the token and then verifies that the price returned is correct.

Unit tests in the tests/ folder are an important part of the Redstone API because they ensure that the API is working correctly. By running the unit tests, you can be sure that the API is returning the correct results.

Thank you for reading ❤


Official site http://redstone.finance
Docs https://docs.redstone.finance
Blog https://blog.redstone.finance

Github https://github.com/redstone-finance

Twitter(x) @redstone_defi
Discord http://redstone.finance/discord