Digital Assets on Tezos

Digital Assets on Tezos

  • Docs
  • TQ Tezos
  • Tezos.com
  • GitHub

›Oracle

Digital Assets on Tezos

  • Welcome

Setup

  • Tezos Client
  • Sandbox

Token Contracts

    FA1.2

    • Introduction
    • FA1.2 LIGO
    • FA1.2 Lorentz
    • FA1.2 Archetype

    FA2

    • FA2-SmartPy
    • FA2 NFT Tutorial LIGO

    Specialized Multisig

    • Introduction
    • Originate and Use

    Transferlist

    • Introduction
    • Originate and Use

    AdminLambda

    • AdminLambda Quick Start

    Vesting

    • Vesting Contract Quick Start

Oracle

  • Oracle Quick Start

Experimental

  • Ticket NFT Auction in Ligo

Run a Public Node with AWS Cloud

  • Running a Public Tezos Node with AWS Cloud
  • Create VPC
  • Key Pair and Github Access Key
  • Deploy the Tezos Updater
  • Deploy Your Tezos Nodes
  • Confirm the Nodes

Getting started with Oracle Contracts on Tezos

Introduction

Smart contracts that require blockchain-external realtime data or events require a trusted oracle, i.e. a trusted smart contract that provides the data on-chain.

What is it useful for?

  • An oracle that provides XTZ/USD prices could allow users to deposit funds that are immediately converted to some on-chain asset and represented as fiat.
  • An oracle that provides weather data could allow a tsunami insurance contract: users purchase coverage from the contract, which pays out when there's a sufficiently severe tsunami in their area
  • A combination of different oracles could be used to provide consensus, for example, where only results published by a majority of the oracles are considered valid.

Setup

  • Follow instructions in Client Setup to set up tezos-client and create a test network wallet
  • Clone lorentz-contract-oracle repo from GitHub and build from source using stack.

The CLI

❯❯❯ lorentz-contract-oracle Oracle --help
Usage: lorentz-contract-oracle Oracle COMMAND
  Oracle contract CLI interface

Available options:
  -h,--help                Show this help text

Available commands:
  print                    Dump the Oracle contract in form of Michelson code
  print-timestamped        Dump the Timestamped Oracle contract in form of
                           Michelson code
  init                     Initial storage for the Oracle contract
  get-value                get value
  update-value             update value
  update-admin             update admin

Originating the contract

Printing the contract

The print command takes a single argument: valueType, the type of the value provided by the oracle.

Note: Until Issue #6 in the repo is fixed, the CLI tool will throw an error if valueType is not nat when printing the contract or the timestamped version.

For example, if nat's are provided:

❯❯❯ lorentz-contract-oracle Oracle print --valueType "nat"

parameter (or (pair %getValue unit
                              (contract nat))
              (or (nat %updateValue)
                  (address %updateAdmin)));
storage (pair nat
              address);
code { CAST (pair (or (pair unit (contract nat)) (or nat address)) (pair nat address));
       DUP;
       CAR;
       DIP { CDR };
       IF_LEFT { DUP;
                 CAR;
                 DIP { CDR };
                 DIP { DIP { DUP };
                       SWAP };
                 PAIR;
                 CDR;
                 CAR;
                 DIP { AMOUNT };
                 TRANSFER_TOKENS;
                 NIL operation;
                 SWAP;
                 CONS;
                 PAIR }
               { IF_LEFT { DIP { DUP;
                                 CAR;
                                 DIP { CDR } };
                           DIP { DROP;
                                 DUP;
                                 DIP { SENDER;
                                       COMPARE;
                                       EQ;
                                       IF {  }
                                          { PUSH string "only admin may update";
                                            FAILWITH } } };
                           PAIR;
                           NIL operation;
                           PAIR }
                         { DIP { DUP;
                                 CAR;
                                 DIP { CDR };
                                 DIP { SENDER;
                                       COMPARE;
                                       EQ;
                                       IF {  }
                                          { PUSH string "only admin may update";
                                            FAILWITH } } };
                           SWAP;
                           PAIR;
                           NIL operation;
                           PAIR } } };

Initial storage

❯❯❯ lorentz-contract-oracle Oracle init --help
Usage: lorentz-contract-oracle Oracle init --initialValueType Michelson Type
                                           --initialValue Michelson Value
                                           --admin ADDRESS
  Initial storage for the Oracle contract

Available options:
  -h,--help                Show this help text
  --initialValueType Michelson Type
                           The Michelson Type of initialValue
  --initialValue Michelson Value
                           The Michelson Value: initialValue
  --admin ADDRESS          Address of the admin.
  -h,--help                Show this help text

Since we're using nat, initialValueType is nat and initialValue can be 0:

❯❯❯ lorentz-contract-oracle Oracle init \
  --initialValueType "nat" \
  --initialValue 3 \
  --admin $ALICE_ADDRESS
Pair 3 "tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr"

Running the origination

NOTE: to use the annotated (timestamped) version, e.g. for nat:

❯❯❯ tezos-client --wait none originate contract NatOracle \
  transferring 0 from $ALICE_ADDRESS running \
  "$(lorentz-contract-oracle Oracle print-timestamped --valueType "nat")" \
  --init "$(lorentz-contract-oracle Oracle init \
  --initialValueType "pair timestamp nat" --initialValue 'Pair "2019-12-10T17:43:53Z" 26871' \
  --admin $ALICE_ADDRESS)" --burn-cap 0.859 --force

NOTE: the nat_oracle.tz contract may be found here

Otherwise:

❯❯❯ tezos-client --wait none originate contract NatOracle \
  transferring 0 from $ALICE_ADDRESS running \
  "$(lorentz-contract-oracle Oracle print --valueType "nat")" \
  --init "$(lorentz-contract-oracle Oracle init \
  --initialValueType "nat" --initialValue 3 \
  --admin $ALICE_ADDRESS)" --burn-cap 0.612

Waiting for the node to be bootstrapped before injection...
Current head: BLE8kx6VhXbk (timestamp: 2020-04-03T15:28:43-00:00, validation: 2020-04-03T15:29:02-00:00)
Node is bootstrapped, ready for injecting operations.
Estimated gas: 20483 units (will add 100 for safety)
Estimated storage: 683 bytes added (will add 20 for safety)
Operation successfully injected in the node.
Operation hash is 'onsEwbbm71wpzgnk6baBGacDzsnKceypEL841STJ6B5V9cA4swr'
NOT waiting for the operation to be included.
Use command
  tezos-client wait for onsEwbbm71wpzgnk6baBGacDzsnKceypEL841STJ6B5V9cA4swr to be included --confirmations 30 --branch BLE8kx6VhXbka6FGjXmKxnH56iypJLYZ9pM5mM3HLKvoVDBiMeS
and/or an external block explorer to make sure that it has been included.
This sequence of operations was run:
  Manager signed operations:
    From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
    Fee to the baker: ꜩ0.002729
    Expected counter: 623928
    Gas limit: 20583
    Storage limit: 703 bytes
    Balance updates:
      tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ............. -ꜩ0.002729
      fees(tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU,154) ... +ꜩ0.002729
    Origination:
      From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
      Credit: ꜩ0
      Script:
        {...}
        Initial storage: (Pair 3 "tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr")
        No delegate for this contract
        This origination was successfully applied
        Originated contracts:
          KT1LVLUsC1WCo4yHzeoDEE8FxxoC7EW6bSyp
        Storage size: 426 bytes
        Paid storage size diff: 426 bytes
        Consumed gas: 20483
        Balance updates:
          tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ... -ꜩ0.426
          tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ... -ꜩ0.257

New contract KT1LVLUsC1WCo4yHzeoDEE8FxxoC7EW6bSyp originated.
Contract memorized as NatOracle.

Make an alias for the resulting address:

❯❯❯ ORACLE_ADDRESS="KT1LVLUsC1WCo4yHzeoDEE8FxxoC7EW6bSyp"

Getting a value

Preparing a view contract

Originate the contract:

❯❯❯ tezos-client --wait none originate contract nat_storage transferring 0 \
  from $ALICE_ADDRESS running "$(lorentz-contract print --name NatStorageContract)" \
  --init 0 --burn-cap 0.295

Make an alias for its address:

❯❯❯ NAT_STORAGE_ADDRESS="KT1ShW17HERZgjUTxSxSc4W3tuWrfLCqBmEi"

See the FA1.2 Quickstart for more info.

Make the parameter

❯❯❯ lorentz-contract-oracle Oracle get-value --help
Usage: lorentz-contract-oracle Oracle get-value --callbackContract ADDRESS
  get value

Available options:
  -h,--help                Show this help text
  --callbackContract ADDRESS
                           Address of the callbackContract.
  -h,--help                Show this help text
❯❯❯ lorentz-contract-oracle Oracle get-value --callbackContract $NAT_STORAGE_ADDRESS
Left (Pair Unit "KT1ShW17HERZgjUTxSxSc4W3tuWrfLCqBmEi")

Get the value

❯❯❯ tezos-client --wait none transfer 0 from $ALICE_ADDRESS to $ORACLE_ADDRESS \
  --arg "$(lorentz-contract-oracle Oracle get-value \
  --callbackContract $NAT_STORAGE_ADDRESS)" --burn-cap 0.000001

Waiting for the node to be bootstrapped before injection...
Current head: BL7fbZE3Gs2V (timestamp: 2020-04-03T15:33:25-00:00, validation: 2020-04-03T15:33:45-00:00)
Node is bootstrapped, ready for injecting operations.
Estimated gas: 31566 units (will add 100 for safety)
Estimated storage: no bytes added
Operation successfully injected in the node.
Operation hash is 'opWqWvkJczWzq5m99svSDzW7HmWY5nCUB1rerDn6utLLH5NJ1dS'
NOT waiting for the operation to be included.
Use command
  tezos-client wait for opWqWvkJczWzq5m99svSDzW7HmWY5nCUB1rerDn6utLLH5NJ1dS to be included --confirmations 30 --branch BL7fbZE3Gs2VkmziY11S4biX9cfuLVnQmLr8r7ALbJukxD4tRSY
and/or an external block explorer to make sure that it has been included.
This sequence of operations was run:
  Manager signed operations:
    From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
    Fee to the baker: ꜩ0.00347
    Expected counter: 623930
    Gas limit: 31666
    Storage limit: 0 bytes
    Balance updates:
      tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm ............. -ꜩ0.00347
      fees(tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU,154) ... +ꜩ0.00347
    Transaction:
      Amount: ꜩ0
      From: tz1bDCu64RmcpWahdn9bWrDMi6cu7mXZynHm
      To: KT1LVLUsC1WCo4yHzeoDEE8FxxoC7EW6bSyp
      Parameter: (Left (Pair Unit "KT1ShW17HERZgjUTxSxSc4W3tuWrfLCqBmEi"))
      This transaction was successfully applied
      Updated storage:
        (Pair 3 0x00003b5d4596c032347b72fb51f688c45200d0cb50db)
      Storage size: 426 bytes
      Consumed gas: 20242
    Internal operations:
      Transaction:
        Amount: ꜩ0
        From: KT1LVLUsC1WCo4yHzeoDEE8FxxoC7EW6bSyp
        To: KT1ShW17HERZgjUTxSxSc4W3tuWrfLCqBmEi
        Parameter: 3
        This transaction was successfully applied
        Updated storage: 3
        Storage size: 38 bytes
        Consumed gas: 11324

Update the value

Make the parameter

❯❯❯ lorentz-contract-oracle Oracle update-value --help
Usage: lorentz-contract-oracle Oracle update-value --newValueType Michelson Type
                                                   --newValue Michelson Value
  update value

Available options:
  -h,--help                Show this help text
  --newValueType Michelson Type
                           The Michelson Type of newValue
  --newValue Michelson Value
                           The Michelson Value: newValue
  -h,--help                Show this help text

Update the value

To update the value to 4:

Waiting for the node to be bootstrapped before injection...
Current head: BMLjQ5pgcmxd (timestamp: 2020-04-03T15:35:39-00:00, validation: 2020-04-03T15:35:44-00:00)
Node is bootstrapped, ready for injecting operations.
Estimated gas: 19463 units (will add 100 for safety)
Estimated storage: no bytes added
Operation successfully injected in the node.
Operation hash is 'ooEf7sgpvhMcUBcn66iMLaWNzs4TEAxb4icjXKF27xM2QPMTGQP'
NOT waiting for the operation to be included.
Use command
  tezos-client wait for ooEf7sgpvhMcUBcn66iMLaWNzs4TEAxb4icjXKF27xM2QPMTGQP to be included --confirmations 30 --branch BMLjQ5pgcmxdN11kfhA2NS4igfSdJeL5HbopDn8LyAckBroWZhi
and/or an external block explorer to make sure that it has been included.
This sequence of operations was run:
  Manager signed operations:
    From: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr
    Fee to the baker: ꜩ0.001259
    Expected counter: 632294
    Gas limit: 10000
    Storage limit: 0 bytes
    Balance updates:
      tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr ............. -ꜩ0.001259
      fees(tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU,154) ... +ꜩ0.001259
    Revelation of manager public key:
      Contract: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr
      Key: edpkvCHgVArnZo9RTP4P6euLTyhE89u73CYjBgsP4wEJbj4quao9oR
      This revelation was successfully applied
      Consumed gas: 10000
  Manager signed operations:
    From: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr
    Fee to the baker: ꜩ0.002123
    Expected counter: 632295
    Gas limit: 19563
    Storage limit: 0 bytes
    Balance updates:
      tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr ............. -ꜩ0.002123
      fees(tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU,154) ... +ꜩ0.002123
    Transaction:
      Amount: ꜩ0
      From: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr
      To: KT1LVLUsC1WCo4yHzeoDEE8FxxoC7EW6bSyp
      Parameter: (Right (Left 4))
      This transaction was successfully applied
      Updated storage:
        (Pair 4 0x00003b5d4596c032347b72fb51f688c45200d0cb50db)
      Storage size: 426 bytes
      Consumed gas: 19463

Setting up a server

While we have everything we need to originate and administer an oracle contract, we'd like to automatically push updates to the contract.

Below are two simple examples of how you can periodically fetch some data and automatically push it to the oracle contract.

Minimal Bash server

A minimal server, written in Bash, could consist of:

  • A Bash script update_value.sh that gets the NEW_VALUE and then calls the update-value entrypoint:
##!/bin/bash
## update_value.sh

NEW_VALUE="$(my_get_new_value_script)

tezos-client --wait none transfer 0 from $ALICE_ADDRESS to $ORACLE_ADDRESS \
  --arg "$(lorentz-contract-oracle Oracle update-value \
  --newValueType "nat" --newValue $NEW_VALUE)" --burn-cap 0.000001
  • A crontab job to run update_value.sh periodically (in the example it's daily at 5:03 pm):
03 05 * * * update_value.sh

Docker Flask server

There is an implementation of the above Bash server in Python, packaged as a Docker image, which:

  • Fetches the latest stock price from Alpha Vantage
  • Runs a "cron job" to push the update to the oracle contract with pytezos every 30 seconds
  • Serves a webpage for debugging

It does the same thing as the Bash script where my_get_new_value_script fetches the latest ticker price from Alpha Vantage.

You can find the project on Github here or view the one-file Python code here.

To get the image from the DockerHub repo, run:

❯❯❯ docker pull tqtezos/oracle-stock-ticker:2.1

The server is configured using environment variables:

  • To generate the TEZOS_USER_KEY parameter, run: echo "$(base64 MY_KEY_FILE.json | tr -d '\n')", where MY_KEY_FILE.json is your Tezos faucet file (see here to get a testnet faucet file).
  • You can get a free ALPHA_VANTAGE_API_KEY from Alpha Vantage
  • Alpha Vantage's Search Endpoint may be used to find ALPHA_VANTAGE_TICKER_SYMBOL's
TEZOS_USER_KEY=".."
ORACLE_ADDRESS="KT1CUTjTqf4UMf6c9A8ZA4e1ntWbLVTnvrKG"
ALPHA_VANTAGE_API_KEY=".."
ALPHA_VANTAGE_TICKER_SYMBOL="AAPL"
FLASK_APP="tq/oracles/ticker.py"

To run the Docker container:

❯❯❯ docker run -d -p 5000:5000 \
  --env TEZOS_USER_KEY=".."
  --env ORACLE_ADDRESS="KT1.." \
  --env ALPHA_VANTAGE_API_KEY=".." \
  --env ALPHA_VANTAGE_TICKER_SYMBOL="AAPL" \
  --env FLASK_APP="tq/oracles/ticker.py" \
  oracle-stock-ticker

Once it's up, it will serve the debug page and update the oracle contract roughly every 30 seconds.

You should be able to view the debug screen at localhost:5000, fetch the latest values using get-value, and use a block explorer to inspect the contract.

You can find a running example of the contract on Carthage.

← Vesting Contract Quick StartTicket NFT Auction in Ligo →
  • Introduction
  • Setup
  • The CLI
  • Originating the contract
    • Printing the contract
    • Initial storage
    • Running the origination
  • Getting a value
    • Preparing a view contract
    • Make the parameter
    • Get the value
  • Update the value
    • Make the parameter
    • Update the value
  • Setting up a server
    • Minimal Bash server
    • Docker Flask server
Digital Assets on Tezos
Copyright © 2021 Tocqueville Group, Inc. All rights Reserved.
  • Home
  • Partnerships
  • Assets
  • Events
  • Blog
  • Jobs
  • Contact
  • TwitterRedditMediumLinkedIn
  • White Paper
  • Position Paper
  • Agora | Governance
  • Developer Portal
  • Start Baking
  • TwitterRedditMediumLinkedIn