Becoming an oracle provider for StarkEx

StarkEx uses external price feeds, which oracle providers pass to the operator. The operator sends the price tick to the StarkEx gateway using the addTransaction method with the OraclePricesTick transaction. StarkEx supports combining prices from a quorum of oracle providers into a single price update.

For more information, see Oracle price tick.

You can become an oracle provider for a StarkEx-powered application by contacting the application operator and completing the following tasks:

  1. Install and run the StarkEx CLI.

  2. Derive your Stark key pair from an Ethereum key pair.

  3. Add the public Stark key to the general configuration.

  4. Start signing prices.

These tasks are described below.

Installing and running the StarkEx CLI

Prerequisites
  • Docker

  • Git

  • 1GB of free disk space in the Docker working directory (/var/lib/docker)

Procedure
  1. Using Git, clone the stark-perpetual repository at https://github.com/starkware-libs/stark-perpetual.

  2. Navigate to the stark-perpetual directory and build the StarkWare Perpetual Docker image.

    $ docker build . -t stark-perpetual

    This command builds a container named stark_perpetual that includes all dependencies and runs various tests.

  3. Run the stark-perpetual cli from the image:

    $ docker run --rm --entrypoint /bin/bash -it stark-perpetual

    A shell opens with a prompt similar to the following:

    `root@17617744386d:/app#`.
  4. Activate the virtual environment:

    root@17617744386d:/app# source build/Release/src/services/perpetual/public/perpetual_public_venv/bin/activate

    The following prefix appears in the command prompt: (perpetual_public_venv)

The StarkEx CLI console is now running. You can view command line help by entering the following command:

(perpetual_public_venv) <prompt>:/app# python src/services/perpetual/public/stark_cli.py
 --help

Deriving your Stark key pair from an Ethereum key pair.

STARK proofs use signatures based on the STARK curve, which differ from Ethereum signatures. So in order to sign on prices for the system you need to create a private and public Stark key pair.

The procedure described here is simple and secure.

Prerequisites
  • An Ethereum private key

Procedure
  1. Create an Ethereum signature using your private Ethereum key and the constant string StarkKeyDerivation, or its hex representation, 0x537461726b4b657944657269766174696f6e.

  2. Use the Keccak hash function to hash r and s signature components to one 256-bit word.

  3. Remove the last five bits of the resulting number to get the 251-bit private Stark key.

  4. Derive the public Stark key from the private Stark key with the get_public method:

    (perpetual_public_venv) <prompt>:/app# python src/services/perpetual/public/stark_cli.py \
    --method get_public \
    --key <private_stark_key>
Example: Deriving a Stark key pair

This example uses the following Ethereum private key and signature to derive the public and private Stark key.

Ethereum private key

0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d

Ethereum signature

fd85e77f5bb436eb90a4c3324a02fea6ef766e6ac85bffccb6e1cdc03479e9ac 058e6fb13916131dd4df1911098e2df71d582ab86281bf2553e55571aa99064b 1c

Ethereum signature hash

keccak256(r, s) = 0x2f008fa70d291380abafd4a98029ff706940d392b2a30d57c09d49a2447407f2

Using the above Ethereum signature hash, you can derive the private and public Stark keys as follows:

  1. Remove the last five bits of the Ethereum signature hash to get the 251-bit private Stark key.

    The resulting private Stark key is 178047D3869489C055D7EA54C014FFB834A069C9595186ABE04EA4D1223A03F

  2. Derive the public Stark key using the get_public method:

    (perpetual_public_venv) :/app# python src/services/perpetual/public/stark_cli.py \
    --method get_public \
    --key 178047D3869489C055D7EA54C014FFB834A069C9595186ABE04EA4D1223A03F

    The resulting public Stark key is 0x1895a6a77ae14e7987b9cb51329a5adfb17bd8e7c638f92d6892d76e51cebcf.

Adding the public Stark key to the general configuration

In order for the STARK proof to be able to use the oracle’s signature, the oracle’s signature must be part of the application’s general configuration, defined in the StarkEx contract for the application.

The application’s general configuration includes a list of public keys that are permitted to sign on each type of synthetic asset. For more information, see Configuration Per Synthetic assetId.

For security reasons, when you add a new public key to the general configuration of a deployed system, StarkEx requires a period of time before the new key goes into effect. This period enables users that do not approve of the change to exit.

As an oracle provider, you cannot directly change the configuration, only the application’s operator can edit the configuration.

This procedure requires the participation of the following parties:

  • the oracle provider

  • the operator

  • StarkWare

Prerequisites
  • A public Stark key.

  • The operator’s consent to add the oracle provider.

Procedure
  1. Oracle provider: Send your public Stark key to the operator that owns the application for which you want to provide oracle price ticks.

  2. operator: For each type of synthetic asset that the oracle provider supports, add the key to the list of trusted public keys in the general configuration. The hash of the general configuration is part of the on-chain contract.

    StarkWare sees the changes and updates the contract.

  3. StarkWare: After a waiting period, StarkWare publishes the updated contract.

Signing prices

Calculating the hash to sign

The hash method generates a number, which is less than FIELD_PRIME, that the sign method uses to generate a signature.

The method first uses the asset_name and oracle_name parameters to generate a number that occupies 252 bits according to the following mapping:

84 bits 128 bits 40 bits

0

asset_name

oracle_name

Then, it uses the price and the timestamp parameters to generate a second number that occupies 252 bits according to the following mapping:

100 bits 120 bits 32 bits

0

price

time_stamp

Finally, it executes a Pedersen hash function using the two generated numbers to generate hash data.

Procedure
  1. Run the StarkEx CLI

  2. Call the hash method:

    (perpetual_public_venv) <prompt>:/app# python src/services/perpetual/public/stark_cli.py \
    --method hash \
    --oracle <oracle> \
    --asset <asset> \
    --price <price> \
    --time <timestamp>

    Where the parameters are as follows:

    oracle

    The hex encoding for your oracle’s name.
    A 40-bit number.

    asset

    The hex encoding of a name you choose for the asset pair. For example: BTCUSD.
    A 128-bit number.

    price

    The hex encoding of the price.
    A 120-bit number, with 18 digits after the decimal point.

    timestamp

    Seconds since the Unix epoch.
    A 32-bit number.

All providers should use the same hex values to refer to the same assets and oracles.

For example, consider that asset refers to BTCUSD, and oracle refers to Maker. All data providers should use the same hex values for BTCUSD, and the same hex values for Maker, in their signatures.

The hash method combines and hashes the parameters.

Example: Calculating the hash to sign

This example uses the following information:

  • oracle = The hex value of Maker, which is 0x4d616b6572.

  • asset = The 128-bit hex value of BTCUSD, which is 0x42544355534400000000000000000000.

  • price: The prices is $11512.34. The hex value of 11512.34 * 1018 is 0x27015cfcb0230820000.

  • timestamp: The timestamp of the transaction is January 1st, 2020, which is 1577836800 seconds after the Unix epoch. The hex value of 1577836800 is 0x5e0be100

The hash function generates the following numbers:

  • first_number = 425443555344000000000000000000004d616b6572, constructed as follows:

    84 bits 128 bits 40 bits

    0, not shown in the result

    425443555344, the hex encoding of BTCUSD, followed by trailing zeroes that occupy the remaining bits

    4d616b6572, the hex encoding of Maker

  • second_number = 0 (100-bit) || price (120-bit) || timestamp (32-bit) = 27015cfcb02308200005e0be100

    100 bits 120 bits 32 bits

    0, not shown in the result

    27015cfcb0230820000, the hex encoding of 11512.34 * 1018

    5e0be100, the hex encoding of 1577836800, which is the number of seconds since the Unix epoch.

    The leading zeroes, which occupy the first 84 bits, do not appear in this example.

  • data_hash = pedersen(first_number, second_number) = 3e4113feb6c403cb0c954e5c09d239bf88fedb075220270f44173ac3cd41858

(perpetual_public_venv) $:/app# python src/services/perpetual/public/stark_cli.py \
--method hash \
--oracle 4d616b6572 \
--asset 42544355534400000000000000000000 \
--price 27015cfcb0230820000 \
--time 5e0be100

Signing the hashed message

Procedure
  1. Run the StarkEx CLI

  2. Call the sign method:

    (perpetual_public_venv) <prompt>:/app# python src/services/perpetual/public/stark_cli.py \
    --method sign \
    --key <key> \
    --data <data>

    Where the parameters are as follows:

    key

    The private Stark key.

    data

    The hash of the message data.

Example: Signing the hashed message

This example uses:

(perpetual_public_venv) <prompt>:/app# python src/services/perpetual/public/stark_cli.py \
--method sign \
--key 178047D3869489C055D7EA54C014FFB834A069C9595186ABE04EA4D1223A03F \
--data 3e4113feb6c403cb0c954e5c09d239bf88fedb075220270f44173ac3cd41858

The resulting signature is:

r: 0x6a7a118a6fa508c4f0eb77ea0efbc8d48a64d4a570d93f5c61cd886877cb920
s: 0x6de9006a7bbf610d583d514951c98d15b1a0f6c78846986491d2c8ca049fd55