Price Feed on AO using 0rbit

gm gm!!

When it comes to interacting with the external world via blockchain, it's often seen as an impossible task. That's where 0rbit comes into play. 0rbit allows you to bring ANY DATA from both the on-chain and off-chain world to the ao process through a decentralized network of 0rbit Nodes.

0rbit is a decentralized, permissionless, and censorship-resistant oracle network built on top of Arweave using ao. It's designed to make accessing and utilizing data on the blockchain easier and more efficient.

Your mission is to create a bot that responds to user queries for token prices, fetching the data using 0rbit's ao process and the CoinGecko API.

Meanwhile, you can meet other builders working on this quest and get help in the 0rbit’s Discord Channel!

Pre-Requisites:

  • Understanding of the ao and aos.

  • aos installed on your system.

  • Some $0RBT. Learn how to get $0RBT here

  • Any Code Editor (VSCode, Sublime Text, etc)

Let's jump into the quest tutorial and finish each step one by one

Checkpoint 0:📦 Initialize The Project

Create a new file named 0rbit-Price-Feed.lua in your project directory.

touch 0rbit-Price-Feed.lua

Checkpoint 1: 📝 Initialize the CONSTANTS

local json = require("json")
 
_0RBIT = "BaMK1dfayo75s3q1ow6AO64UDpD9SEFbeE8xYrY2fyQ"
_0RBT_TOKEN = "BUhZLMwQ6yZHguLtJYA5lLUa9LQzLXMXRfaq9FVcPJc"
 
BASE_URL = "https://api.coingecko.com/api/v3/simple/price"
FEE_AMOUNT = "1000000000000" -- 1 $0RBT

Breakdown of the above code:

  • json: This module is required to destruct the stringified JSON data. In this case, you interact with an API (api.coingecko.com) to fetch cryptocurrency prices. The data returned by this API is typically in JSON format. Therefore, you must parse this JSON data to extract the required information..

  • _0RBIT: The processId of the 0rbit process.

  • _0RBT_TOKEN: The processId of the $0RBT process.

  • BASE_URL: The API URL you want to fetch data from. In this case, we are fetching cryptocurrency prices from the CoinGecko API.

  • FEE_AMOUNT: The amount of $0RBT you want to send to the 0rbit process for the request.

For more detailed information on how to use the JSON module, you can visit the documentation here

Checkpoint 2: 🛠 Initialize the Variables

TOKEN_PRICES = TOKEN_PRICES or {
    BTC = {
        coingecko_id = "bitcoin",
        price = 0,
        last_update_timestamp = 0
    },
    ETH = {
        coingecko_id = "ethereum",
        price = 0,
        last_update_timestamp = 0
    },
    AR = {
        coingecko_id = "arweave",
        price = 0,
        last_update_timestamp = 0
    }
}
ID_TOKEN = ID_TOKEN or {
    bitcoin = "BTC",
    ethereum = "ETH",
    arweave = "AR"
}

Breakdown of the above code:

  • TOKEN_PRICES: The table stores the latest prices and other details of the tokens you want to fetch. If the table is not already defined, we initialize it with default values for Bitcoin (BTC), Ethereum (ETH), and Solana (SOL).

  • ID_TOKEN: The table stores the mapping of the token IDs from the CoinGecko API to the token symbols you want to fetch.

Yayy! Keep Going and remember, every small step counts towards progress! 🚀

Checkpoint 3: 📦 Create Functions

Get Token Price Function

The getTokenPrice function returns the token's price from the TOKEN_PRICES table.

function getTokenPrice(msg)
    local token = msg.Tags.Token
    local price = TOKEN_PRICES[token].price
    if price == 0 then
        Handlers.utils.reply("Price not available!!!")(msg)
    else
        Handlers.utils.reply(tostring(price))(msg)
    end
endg

Breakdown of the above code:

  • token: Extract the token from the incoming message.

  • price: Get the token's price from the TOKEN_PRICES table.

  • If the price is 0, send a message stating that the price is not available.

  • If the price is not 0, send the price to the sender.

Fetch Token Price Function

The fetchPrice function fetches the token's price from the CoinGecko API using 0rbit's Get-Real-Data handler.

function fetchPrice()
    local url;
    local token_ids = "";

    for _, v in pairs(TOKEN_PRICES) do
        token_ids = token_ids .. v.coingecko_id .. ","
    end

    url = BASE_URL .. "?ids=" .. token_ids .. "&vs_currencies=usd"

    Send({
        Target = _0RBT_TOKEN,
        Action = "Transfer",
        Recipient = _0RBIT,
        Quantity = FEE_AMOUNT,
        ["X-Url"] = url,
        ["X-Action"] = "Get-Real-Data"
    })
    print(Colors.green .. "GET Request sent to the 0rbit process.")
end

Breakdown of the above code:

  • for _, v in pairs(TOKEN_PRICES): Iterate over the TOKEN_PRICES table to get a token.

  • token_ids: Concatenate all the tokens coingecko_id.

  • url: The final URL to fetch the token prices.

  • Send: Transfer 1 $0RBT to the 0rbit process and make a GET request. With this, we initiate a transfer of 1 $0RBT to the 0rbit process and execute a GET request.

    • Target: This denotes the process to be pinged with the following Action, specifically the 0rbit Token Process.

    • Action: This signifies the task to be carried out, in this case, the transfer of 1 0rbit token from the current process to the 0rbit process ID.

    • Recipient: This indicates the receiver of the transfer, which, in this context, is the 0rbit oracle's process.

    • Quantity: This denotes the amount intended for transfer.

    Additionally:

    • The ["X-Url"] tag specifies the URL from which the data is to be fetched.

    • The ["X-Action"] tag specifies the action to be performed.

      The "X-" prefix in these tags is a convention used to denote forwarded tags. Forwarded tags refer to additional information included in a message that is passed along to subsequent messages or handlers.

Receive Data Function

The receiveData function is called when the 0rbit process sends the fetched data to the process.

function receiveData(msg)
    local res = json.decode(msg.Data)
    for k, v in pairs(res) do
        TOKEN_PRICES[ID_TOKEN[k]].price = tonumber(v.usd)
        TOKEN_PRICES[ID_TOKEN[k]].last_update_timestamp = msg.Timestamp
    end

    print(Colors.green .. "Token prices updated.")
end

Breakdown of the above code:

  • res: Parse the JSON data received from the 0rbit process.

  • for k, v in pairs(res): Iterate over the parsed data.

  • Update the token's price and last_update_timestamp in the TOKEN_PRICES table.

Remember, just like planets in space, you're moving forward on your own journey. Keep taking steps and you'll reach your destination. 🚀

Checkpoint 4: 🔄 Create Handlers

Get Token Price Handler

The GetTokenPrice handler is called when a process wants to get the latest price of a token.

Handlers.add(    
  "GetTokenPrice",    
  Handlers.utils.hasMatchingTag("Action", "Get-Token-Price"), 
  getTokenPrice
)

Breakdown of the above code:

  • GetTokenPrice: The name of the handler.

  • Handlers.utils.hasMatchingTag("Action", "Get-Token-Price"): Checks if the message action tag is Get-Token-Price

  • getTokenPrice: The function that sends the latest price of a token from the TOKEN_PRICES table.

Fetch Price Handler

This handler will fetch the token prices by sending request to 0rbit

Handlers.add(
    "FetchPrice",
    Handlers.utils.hasMatchingTag("Action", "Fetch-Price"),
    fetchPrice
)

Breakdown of the above code:

  • FetchPrice: The name of the handler.

  • Handlers.utils.hasMatchingTag("Action", "Fetch-Price"): Checks if the message action tag is Cron

  • fetchPrice: The function that sends a GET Request to 0rbit process to fetch the token prices.

Receive Data Handler

The ReceivingData handler is called when the 0rbit process sends the fetched data to the process.

Handlers.add(
    "ReceivingData",
    Handlers.utils.hasMatchingTag("Action", "Receive-Response"),
    receiveData
)

Breakdown of the above code:

  • ReceivingData: The name of the handler.

  • Handlers.utils.hasMatchingTag("Action", "Receive-Response"): Checks if the message action tag is Receive-Response

  • receiveData: The function that updates the token prices in the TOKEN_PRICES table.

You're almost there! Keep up the great work, and let's tackle the next checkpoint together! 🎉

Checkpoint 5: 🛠️ Run the Process

Open your terminal

Open your terminal in the directory that contains 0rbit-Price-Feed.lua and enter the following command:

aos 0rbitPriceFeed --cron 30-seconds

The above command will create a new process with the name 0rbitPriceFeed and set a cron job every 30 seconds.

Load your process

Load your script into the process:

aos> .load 0rbit-Price-Feed.lua

Fund your process

Transfer some $0RBT to your processID.

Check the Token Price

aos> Send({ Target = ao.id, Action="Get-Token-Price", Tags = { Token = "AR" }})

Voila! You have successfully created a Price Feed Process. 🎉

I hope you have learned something today with this quite a long blog. Moreover, you can find the complete code here.

If you have any queries feel free to DM us on Twitter or join our Discord community to know more about 0rbit.

Happy Building!! 🧱💫🚀

Subscribe to 0rbit
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.