Journey Through Cairo X — Inter-realm Communications With Empiric Oracle

Darlington Nnam
6 min readSep 30, 2022

--

Welcome to the tenth article in our series, “Journey through Cairo”. In the last article we got to write our first unit test using Protostar, today we’d be going through something more exciting..

As always, if you are just joining us mid-flight, you could catch the last episode here.

Blockchain Oracles

Blockchain Oracles i’d say are one of those concepts that sounds weird on your first encounter. Let’s take a moment to dive right into how they came into existence..

Oracles in Greek mythology, were these special persons also known as priests/priestesses, that had the ability to interact and communicate with the divine/spiritual realm. They were mostly seen as the mouthpiece of the gods, and the only way to know the thoughts of the gods at every point in time.

When you apply the oracle concept to blockchains, you get Blockchain Oracles..so could we then say Blockchain Oracles enable inter-realm communications? smiles.

Let’s just keep moving.

The Blockchain is Deterministic..

Blockchains are programmed to be deterministic…by this i mean that blockchains are created to be an isolated system (think of a computer with no internet connection), and reaches consensus on data that lies within its ledger.

Whilst this is very important, as it helps the blockchain attain high degree of accuracy/certainty, thus making it a trust-less system, it poses a lot of limits to what becomes achievable using smart contracts.

One of the core goals we look forward to, is mass adoption, but how do we achieve this if we can’t interact with the outside world? financial smart contracts need market information to determine settlements, insurance smart contracts needs IoT, etc.

The big question becomes how do we interact with the outside world, without sacrificing the deterministic feature of the Blockchain? Of course we can’t just depend on a centralized entity to provide these information..that negates the core tenets of decentralization, cause there’s a tendency that the centralized entity might suddenly experience downtime or worse still be corrupted.

These issues are what Blockchain Oracles try to solve, by providing a decentralized means for Smart contracts running on the blockchain to effectively interact with the outside world, without sacrificing its deterministic nature.

For a deeper dive into how Oracles work, check out this article from Chainlink here.

Empiric — Reimagining Oracles on Starknet

Whilst Chainlink solves the Oracle problem on Ethereum, Empiric attempts to solve the oracle problem on Starknet.

Leveraging Zk-technology, they’ve created an architecture that is both transparent, composable and decentralized.

Today, we’d be exploring oracles, by building our first hybrid smart contract, using Empiric’s price feed feature. To create reliable Price feeds, Empiric works with different liquid exchanges and market makers who signs their proprietary data and sends it directly on-chain.

Let’s get started building, to see how this works.

Getting Started

As always, we’d be using protostar, so if you still haven’t installed it, checkout my guide here.

Project description

A simple project that users could use to get the price of BTC, ETH and SOL.

Requirement

Basic knowledge of writing Starknet Contracts.

Project initialization

Having installed Protostar, we’d initialize a new project by running the command:

protostar init

Once we do that, we’d be asked for the project name and lib name, which we’d need to input to successfully create a new project.

Writing Contract

Since we’ve gone through most of these in our previous articles here , we wouldn’t spend so much time, explaining some of the codes.

imports

%lang starknetfrom starkware.cairo.common.cairo_builtins import HashBuiltin

constants

const EMPIRIC_ORACLE_ADDRESS = 0x012fadd18ec1a23a160cc46981400160fbf4a7a5eed156c4669e39807265bcd4;const ETH_KEY = 28556963469423460; const BTC_KEY = 27712517064455012;const SOL_KEY = 32492132765102948;const AGGREGATION_MODE = 120282243752302;  // str_to_felt("median")

Over here, we define the constants we’d be needing for our contract. As you can see, we’ve got 5 constants:

  1. EMPIRIC_ORACLE_ADDRESS — Specifies the address where Empiric’s contract is deployed.
  2. ETH_KEY — Is the lowercased utf8-encoded string of “eth/usd”. This serves as a pointer to inform the oracle of what pairs you need.
  3. BTC_KEY — Is the lowercased utf8-encoded string of “btc/usd”.
  4. SOL_KEY — Is the lowercased utf8-encoded string of “sol/usd”.
  5. AGGREGATION_MODE — this specifies the aggregation process you want to follow to get your data. Currently there’s only a median aggregation mode, so we convert the string “median” to felt, and pass it on, as an argument to our oracle.

contract Interface

@contract_interfacenamespace IEmpiricOracle{  func get_value(key : felt, aggregation_mode : felt) -> (     value : felt,     decimals : felt,     last_updated_timestamp : felt,     num_sources_aggregated : felt  ){}}

An interface in Cairo, is used to interact with an external Contract. Here we create an interface IEmpiricOracle, which contains the function get_value which we want to interact with.

This function takes in the key (which specifies the price pair we want), and the aggregation mode, and returns the value (asset price), number of decimals, the last updated timestamp, and the number of sources aggregated.

Getting Bitcoin’s Asset Price

@viewfunc btc_price{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}() -> (price: felt){let (
price,
decimals, last_updated_timestamp, num_sources_aggregated) = IEmpiricOracle.get_value( EMPIRIC_ORACLE_ADDRESS, BTC_KEY, AGGREGATION_MODE);return (price,);}

Having specified all constants, and our contract interface, we move unto creating our first view function, that returns the USD price of Bitcoin.

As you can see, we make a call to the get_value function of Empiric’s oracle, using the specified interface, passing in 3 arguments rather than the expected 2. This is because when you make a call to an external contract using an interface, you must specify the address of that contract, as the first argument.

We then return the price of the asset from Empiric.

Getting Ethereum’s Asset Price

@viewfunc eth_price{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}() -> (price: felt){let (
price,
decimals, last_updated_timestamp, num_sources_aggregated) = IEmpiricOracle.get_value( EMPIRIC_ORACLE_ADDRESS, ETH_KEY, AGGREGATION_MODE);return (price,);}

Here we also repeat the same thing, but this time with a different key.

Getting Solana’s Asset Price

@viewfunc sol_price{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}() -> (price: felt){let (
price,
decimals, last_updated_timestamp, num_sources_aggregated) = IEmpiricOracle.get_value( EMPIRIC_ORACLE_ADDRESS, SOL_KEY, AGGREGATION_MODE);return (price,);}

Deploying Contract

We’d run the Protostar deploy command, passing in the test network:

protostar deploy ./build/main.json --network testnet 

Once deployed, we’d get our contract address and transaction hash outputted on the screen, which we can copy and interact with on Voyager.

Reading Asset Prices From Voyager

Having deployed our contract, we can now interact with it through Voyager.

Now, let’s try calling the btc_price function:

And for Eth’s price:

And lastly, Solana’s price:

As you can see, it returns the price of BTC ETH and SOL, as at the time of this writing.

Notice how long the string of numbers are. This is due to the decimals (18).

Conclusion

Hurray! you just witnessed your first inter-realm communication using a Blockchain Oracle.

For a deeper dive into Oracles, i urge you to check out this article by Maksimjeet Chowdhary here.

Empiric also provides price feeds for more assets which you can experiment and build cool stuffs with here. They also recently went through an Audit and upgraded some of their contracts, so always go through the docs here, in case there are changes to the existing oracle address.

PS: Empiric just recently announced their VRF feature, which i would be doing a walk-through on, once the official docs are out, so follow me on the following socials, especially Twitter, so you don’t miss out when it drops:

Twitter: https://twitter.com/0xdarlington

LinkedIn: https://www.linkedin.com/in/nnamdarlington

Github: https://github.com/Darlington02

--

--