Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

redstone-evm-connector

Package Overview
Dependencies
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

redstone-evm-connector

Putting data directly into storage is the easiest to make information accessible to smart contracts. However, the convenience comes at a high price, as the storage access is the most costly operation in [EVM](https://ethereum.github.io/yellowpaper/paper.p

  • 2.1.26
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

🔗 RedStone EVM connector

Putting data directly into storage is the easiest to make information accessible to smart contracts. However, the convenience comes at a high price, as the storage access is the most costly operation in EVM (20k gas for 256bit word ~ $160k for 1Mb checked 30/08/2021) making it prohibitively expensive to use.

RedStone EVM connector implements an alternative design of providing data to smart contracts. Instead of constantly persisting data on EVM storage, the information is brought on-chain only when needed (on-demand fetching). Until that moment, the data remains available in the Arweave blockchain where data providers are incentivised to keep information accurate and up to date. Data is transferred to EVM via a mechanism based on a meta-transaction pattern and the information integrity is verified on-chain through signature checking.

💡 How it works

At a top level, transferring data to an EVM environment requires packing an extra payload to a user's transaction and processing the message on-chain.

image.png

Data packing (off-chain data encoding)

  1. Relevant data needs to be fetched from the streamr network and the RedStone cache layer (as a backup source)
  2. Data is packed into a message according to the following structure

image.png

  1. The package is appended to the original transaction message, signed and submitted to the network

All of the steps are executed automatically by the ContractWrapper and transparent to the end-user

Data unpacking (on-chain data verification)

  1. The appended data package is extracted from the msg.data
  2. The data signature is verified by checking if the signer is one of the approved providers
  3. The timestamp is also verified checking if the information is not obsolete
  4. The value that matches a given symbol is extracted from the data package

This logic is executed in the on-chain environment and we optimised the execution using a low-level assembly code to reduce gas consumption to the absolute minimum

Benchmarks

We work hard to optimise the code using solidity assembly and reduce the gas costs of our contracts. Below there is a comparison of the read operation gas costs using the most popular Chainlink Reference Data, the standard version of Redstone PriceAware contract and the optimised version where provider address is inlined at the compilation time. The scripts which generated the data together with results and transactions details could be found in our repository.

Screenshot-2021-09-05-at-17-18-25.png

📦 Installation

Install redstone-evm-connector from NPM registry

# Using yarn
yarn add redstone-evm-connector

# Using NPM
npm install redstone-evm-connector

🔥 Getting started

1. Modifying your contracts

You need to apply a minium change to the source code to enable smart contract to access data. Your contract needs to extend the PriceAware contract and override the implementation of isSignerAuthorized function.

import "redstone-evm-connector/lib/contracts/message-based/PriceAware.sol";

contract YourContractName is PriceAware {

  function isSignerAuthorized(address _receviedSigner) public override virtual view returns (bool) {
    // Put your logic of signers authorisation here
    // You can check check evm addresses for providers at: https://api.redstone.finance/providers
    return _receviedSigner == 0x0C39486f770B26F5527BBBf942726537986Cd7eb; // redstone main demo provider

    // Uncomment for redstone-stocks demo provider
    // return _receviedSigner == 0x926E370fD53c23f8B71ad2B3217b227E41A92b12;

    // Uncomment for redstone-rapid demo provider
    // return _receviedSigner == 0xf786a909D559F5Dee2dc6706d8e5A81728a39aE9;

    // Uncomment for redstone-avalanche price feed (it has 2 authorised signers)
    // return _receviedSigner == 0x3a7d971De367FE15D164CDD952F64205F2D9f10c
    //   || _receviedSigner == 0x41ed5321B76C045f5439eCf9e73F96c6c25B1D75;

    // Uncomment for redstone-avalanche-prod price feed (it has 12 authorised signers)
    // return _receviedSigner == 0x981bdA8276ae93F567922497153de7A5683708d3
    //   || _receviedSigner == 0x3BEFDd935b50F172e696A5187DBaCfEf0D208e48
    //   || _receviedSigner == 0xc1D5b940659e57b7bDF8870CDfC43f41Ca699460
    //   || _receviedSigner == 0x1Cd8F9627a2838a7DAE6b98CF71c08B9CbF5174a
    //   || _receviedSigner == 0xbC5a06815ee80dE7d20071703C1F1B8fC511c7d4
    //   || _receviedSigner == 0xe9Fa2869C5f6fC3A0933981825564FD90573A86D
    //   || _receviedSigner == 0xDf6b1cA313beE470D0142279791Fa760ABF5C537
    //   || _receviedSigner == 0xa50abc5D76dAb99d5fe59FD32f239Bd37d55025f
    //   || _receviedSigner == 0x496f4E8aC11076350A59b88D2ad62bc20d410EA3
    //   || _receviedSigner == 0x41FB6b8d0f586E73d575bC57CFD29142B3214A47
    //   || _receviedSigner == 0xC1068312a6333e6601f937c4773065B70D38A5bF
    //   || _receviedSigner == 0xAE9D49Ea64DF38B9fcbC238bc7004a1421f7eeE8
  }

After applying the mentioned change you will be able to access the data calling the local getPriceFromMsg function. You should pass the symbol of the asset converted to bytes32:

uint256 ethPrice = getPriceFromMsg(bytes32("ETH"));

You can see all available assets and symbols in our web app.

2. Updating the interface

You should also update the code responsible for submitting transactions. If you're using ethers.js, we've prepared a dedicated library to make the transition seamless.

Contract object wrapping

First, you need to import the wrapper code to your project

// Typescript
import { WrapperBuilder } from "redstone-evm-connector";

// Javascript
const { WrapperBuilder } = require("redstone-evm-connector");

Then you can wrap your ethers contract pointing to the selected Redstone data provider. You can also specify the single asset that you would like to pass to your contract. It helps to decrease transactions GAS cost, because in this case only the data for the provided asset will be passed to the contract.

const yourEthersContract = new ethers.Contract(address, abi, provider);

// Connecting all provider's prices (consumes more GAS)
const wrappedContract = WrapperBuilder
                          .wrapLite(yourEthersContract)
                          .usingPriceFeed("redstone");

// Connecting a single price from selected provider
const wrappedContract = WrapperBuilder
                          .wrapLite(yourEthersContract)
                          .usingPriceFeed("redstone-stocks", { asset: "AAPL" });

// Connecting a custom provider (with a custom price feed configuration)
// You can check example price feed configurations here: https://github.com/redstone-finance/redstone-evm-connector/tree/master/utils/v2/connector/impl/default-data-sources
const wrappedContract = WrapperBuilder
                          .wrapLite(yourEthersContract)
                          .usingPriceFeed("custom", {
                            asset: "AAPL",
                            dataSources: {
                              sources: [...],
                              valueSelectionAlgorithm: "first-valid",
                              timeoutMilliseconds: 10000,
                              maxTimestampDiffMilliseconds: 150000,
                              preVerifySignatureOffchain: true,
                            }
                          });

Now you can access any of the contract's methods in exactly the same way as interacting with the ethers-js code:

wrappedContract.executeYourMethod();
Mock provider

If you'd like to use the wrapper in a test context, we recommend using a mock provider when you can easily override the price to test different scenarios:

To test contracts with mock provider please be sure to authorize the following signer address: 0xFE71e9691B9524BC932C23d0EeD5c9CE41161884. But don't use this address in production, because its private key s publicly known.

Example authorization in contract
import "redstone-evm-connector/lib/contracts/message-based/PriceAware.sol";

contract YourContractName is PriceAware {

  function isSignerAuthorized(address _receviedSigner) public override virtual view returns (bool) {
    return _receviedSigner == 0xFE71e9691B9524BC932C23d0EeD5c9CE41161884; // mock provider address
  }
Option 1. Object with prices
const wrappedContract = WrapperBuilder.mockLite(yourEthersContract).using({
  ETH: 2005,
  BTC: 45000,
  REDSTONE: 100000,
});
Option 2. Function (timestamp => PricePackage)
function mockPriceFun(curTimestamp) {
  return {
    timestamp: curTimestamp - 5000,
    prices: [
      { symbol: "ETH", value: 2005 },
      { symbol: "BTC", value: 45000 },
    ],
  };
}

const wrappedContract =
  WrapperBuilder.mockLite(yourEthersContract).using(mockPriceFun);

We're also working on a wrapper for the truffle/web3 contracts. Please let us know if you need a solution for other frameworks as well.

Alternative solutions

If you don't want to modify even a single line of your contract, it's possible to use an alternative solution based on the Proxy pattern. This approach intercepts a transaction at a proxy stage, extracts the price data and delegates the original transaction to your contract. Another advantage of the solution is allowing any contract (including 3rd party ones) to access the data. However, these benefits come at the cost of higher gas consumption. If you're interested in using this approach take a look at the contracts located in the storage-based folder and reach out to us if you need help setting up your environment.

✅ Working demo

You can see examples of redstone-evm-connector usage in our dedicated repo with examples.

👨‍💻 Development and contributions

The codebase consists of a wrapper written in typescript which is responsible for packing the data and solidity smart contracts that extract the information. We encourage anyone to build and test the code and we welcome any issues with suggestions and pull requests.

Installing the dependencies

yarn install

[Optional] Set up secrets file

If you want to run the scripts located in the ./scripts folder from your ethereum wallet you should create a .secret.json file based on the sample.secret.json and update it with your private key. The .secret.json file should not be commited when you push your changes to github (it's added to .gitignore).

Compiling and running the tests

yarn test

FAQs

Package last updated on 20 Aug 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc