Weather Oracle with Aeternity from scratch

Jeevanjot Singh
8 min readNov 6, 2020

--

Greetings Everyone,

I was wondering about other Oracle technologies and I stumbled across Aeternity which is a blockchain technology on its own with many inbuilt features that Ethereum now requires third parties to handle them for its own Technology. Ethereum is a good blockchain and with its current developed protocols migrating to Layer 2 that adds up more user-friendliness to it. While Ethereum Uses Solidity (Programming Language) For its Virtual Machines called EVM, Aeternity Uses Sophia (Programming Language) for its own Virtual Machines called FATE.

One of the main features of Aeternity blockchain is it’s Native Oracle Support. Native oracle means you will have the control to create requests that require outside data used inside your smart contracts and you can set automated response or maybe respond yourself manually.

In this tutorial, I made an automatic responding backend that responds to the current Temperature (In Kelvin) whenever a query created for an oracle inside a smart contract.

You will Learn

  • How to use AEproject CLI
  • How to Interact with Contracts using Ae SDK
  • How to Listen to events using Ae Middleware Websockets and API
  • Using Third-Party API to respond automatically from backend
  • How to make unit tests for Sophia

Prerequisites

Starting Now

Create a directory to have your project file on it

  • Use quickstart guide to perform necessary steps, Like creating Project files with init command and if you still don’t want to run a local node (Which requires docker) that’s fine, just skip those steps.
  • Now there is a file called ExampleContract.aes. For simplicity, Let’s keep the file name because it is used in deployment and testing.
  • Remove all previous code and add the below code in the file.

Brief Explanation for above code

datatype event = QueryCreated(int)

This line declares a new event with the type of data it will be seen by us.

record state = {...}

This block declares state variables.

stateful entrypoint init ()

This calls register_oracle with default values 5,500 at the deployment of the contract (Just like a constructor in solidity) and also initializes state variables.

entrypoint get_queries (): int = state.queries

That is just a method that returns the total number of queries register.

The code blocks are not structured with best practices, It is advised to take community help to learn more sophia coding so they can find bugs or structure your code in understandable manner, etc.

stateful function register_oracle(...)

This register oracle with the fee to take for each query and TTL of Relative type.

TTL is time to live for your oracle on-chain, Here Two types can be found, Relative means from Current block and Fixed means from Genesis block.

payable stateful entrypoint create_query(...)

This here is to create a query with the recently created oracle and fire an event after this.

It requires all the parameters to be filled, Like your question (string), The fee, and its own TTL (2 types) One that tells for how much wait to accept the response and other is How much wait till the response stays on-chain.

stateful entrypoint respond(…)

These methods fulfill the query with an answer (called the response), required query id, and string (answer)

Now as you learn the working of Sophia you will understand how it is returning read data to find stored values inside the contract to further use them in our call.

Deploy Contract

Now if you using docker you can use simple commands from docs for local test-net but you can use cloud test-net that already hosted by Aeternity

Inside the Deployment Folder, You should check the file called deploy.js Which defines which file to deploy

For local test-net

aeproject deploy

For Global test-net :)

aeproject deploy -n testnet

At this point, you might get some Errors That asks about some required modules, Just use the below code for the package.json file.

Run npm I or yarn at this point to install those new dependencies. Run the deploy command again.

You have your contract deployed,

If you encounter any compiler issues for using the local test-net then run aeproject compiler to run local compiler for you. If you wondering what keys or accounts used to deploy contract then it’s already setup for you, I Will explain in this article below to get them and use them.

Get your accounts (keypairs)

Use AEproject command to do so (Run aeproject -h to learn more)

aeproject export-config

Which exports all your configs (including keypairs) to a default file in root directory of the project called aeprojectConfig.json and also print our that content in your terminal.

Using contract in Frontend

Create a new folder for your index.html, js, and CSS, or for frameworks just initialize your project with their appropriate CLI tools. I use Vue most of the time(currently, my personal favorite) but for this tutorial, I am using plain HTML and jquery tools with semantic UI touch.

Checkout the frontend folder here:

Inside frontend/js/contract.js you can see I defined contracts with the current contract code and its address in their variables.

Now running that front will be easy, Just use a simple utility package like live-server from npm

Note:

Inside main.js file (inside js directory of frontend), I have initialized keypair that I want to use to interact with the contract(Create a new query), But that won’t be necessary if you are going to base app from Aeternity, Where you can just use global object and declare client like Ae.Aeapp() The tutorial series https://dacade.org/ae-dev-101 is well organized to learn development with aeternity and this specific video shows how to do it (you might require SDK version 6.1.2 (according to a warning from video description).

More here https://dacade.org/ae-dev-101/chapter/2 (3rd video)

Using contract in Backend

Now for backend use, we need a way to check when a new query gets created so we can fulfill its response and also we need to get what query comes not just when a query comes in.

Checkout backend directory here

Emitting Events

Just like solidity, Sophia has its own way of Fire events on-chain just differences here and there but you can learn more about this here.

Chain.event(QueryCreated(state.queries))

The above line (inside contract) emits the events and the code to declare it is given as the first line of the contract (see above).

Capture Events (Listening)

Aeternity provides a middleware tool that has an access point for WebSockets & Http/Https. We will use a WebSocket connection to listen to our contract transactions and HTTP for events Info.

Checkout WebSockets and how to use them here. We will use Object payload and target as our contract_address to get transactions that related to our contract as defined in the object’s target (see the below line)

connection.sendUTF(`{"op":"Subscribe",  "payload": "Object", "target":"${contract_address}"}`);

Once completed run the WebSocket and you will start to receive the transactions and their hash.

Once you have transactions, I am using Axios in my backend to run the hash with the below URL. (<tr_HASH>)

https://testnet.aeternity.io/v2/transactions/<tr_HASH>/info

This will return the info for your transactions including the arguments you want to return from the event.

A transaction that creates Query

If you read Events then you will know what the log and data have as values.

In the above image, the second element of the log array (event data in this case) returns 2 which I am returning from the contract, That is the id of the query that I am saving in the contract mapped with the query id(address), So 2 will return the latest query from contract (which is 2nd) address (for e.g. oq_rd14CTVWVwwXeqMR8zyuyMCVstZC4hVbJ566MS9mCrTFCKaJ1) that I will use to respond answer to.

entrypoint get_query_address(id: int) :oracle_query(string, string)=       state.id_query[id]

Once I have it then all I need to perform is API Call and Respond answer to it
https://github.com/genievot/aeternity-simple-oracle/blob/master/consumer/backend/index.js#L80

A transaction that gives a response to a query

And after that, My query will have the appropriate answer (Temperature in Kelvin 289.15).

Unit Tests

To perform unit testing, AEproject provides its own client and environment support. It uses Mocha Framework to handle testing.

Inside the test directory, You will find the contract name file exampleTest.js where the tests are defined.

Assuming we are using local node

let ownerKeyPair = wallets[0];

The above lines get the first element in the wallets object array and assign it to a variable.

describe('name_of_test', function() { //callback })

The above describes and groups the contract tests.

before(async () => { ... })

The above hook is defined inside describe, Which runs before the first test.

it('Test name', async () => {})

Inside it you define your test and add conditions to check whether it gives the result you expect or not.

You can either use local chain and global objects or define custom SDK objects, Learn more at https://aeproject.gitbook.io/aeproject/developer-documentation/aeproject-cli/testing#run-unit-tests

Checkout https://github.com/genievot/aeternity-simple-oracle/blob/master/test/CreateOracle.js File to learn more about how unit tests can be written.

Real-World Test

Visit: —
https://github.com/genievot/aeternity-simple-oracle/blob/master/README.md

https://www.youtube.com/watch?v=gPuhMhC-q-Y

Aeternity Public Key Structure

ak_QWxf7hEM8CFPi3SmWSNTByQDKE2E5fgntPbEDwi7xvfb7SWwY

and Custom Name Service by Aeternity

jeevanjotsingh.chain

--

--