Introduction

To unleash the power of the rules engine, the data used to determine rule outcomes must be onchain. The O2 API enables you to programmatically push off-chain data onchain in a reliable way. No need to build and maintain the infrastructure yourself.

The potential reasons are many, however to make it more concrete let’s cover an example.

Consider a trading card game where each card is an NFT. As you utilize these cards in battle they are leveled up, unlocking new attacks, but the card level is stored in offchain metadata. New players are granted a starter pack of these cards to begin playing. Your game has a marketplace to enable players to buy and sell new cards and build out their deck.

The crux is that you only want the starter NFTs to be tradeable once they’ve reached a particular level to ensure players are actually participating in the game before they are able to sell their gifted NFTs.

As it stands now this rule isn’t possible because the level of the card is not readable onchain. Time to bring it onchain!

Pre-requisites

Before you begin, make sure you have the following:

  • O2 Oracle Dashboard Account: You will need an account in the O2 Oracle dashboard to access your apps and property lists.
    At the Permissionless IV Hackathon and need an account? Come talk to us at our table!
  • Node.js Installed: The JavaScript examples in this guide require Node.js (18.x or later) to run.

Once you have these prerequisites, you’ll be ready to follow the step-by-step instructions in this guide.

Create Your Property List

The O2 Oracle API deploys a smart contract to store the data you need onchain to power rules. Once you’re logged into the O2 Dashboard, navigate to an existing app or create a new one.

Once you’ve selected your app, create the property list to store card level data. Select the Create Property List button to proceed.

Now, it’s time to set up a property to hold the card level data. As you can see below the best index type for this is uint256 which represents the tokenId of the specific NFT that has leveled up. The level property is also set as the uint256 type because it will store a simple integer indicating the level of that card.

When you save the property and return to the list view you’ll notice the status is draft. In this example you can go ahead and publish. As you develop more sophisticated property lists you can delay publishing until all of your properties have been drafted and fine tuned.

Now you have an onchain place to store card level data! Next, you’ll learn how to add items to this list that can be used in the evaluation of rules.

Push Data Onchain

You can use the same dashboard to add data to the property list, which is useful for quick testing. Let’s look into how to add an item to the property list via API since that best fits the example scenario, but first let’s make sure you have the necessary information to do so:

Add or Update Property List Items

Below you will create or update a property list item. You can pass multiple rows in a single call.

The index value for the row items should match the tokenId of the NFT card you intend to level up. In the example below, the tokenId is 333.

const appId = "your-app-id"; // from previous step
const propListId = "your-property-list-id"; // from previous step
const accessToken = "your-access-token";

const addPropertyListItem = async () => {
  const response = await fetch(
    `https://sandbox.api.o2-oracle.io/apps/${appId}/propertylists/${propListId}/rows`,
    {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${accessToken}`,
      },
      body: JSON.stringify({
        operation: "create", // or "update" to update an existing item
        rows: {
          333: {
            level: 6,
          },
        },
      }),
    }
  );
  console.log(await response.json());
};

addPropertyListItem();

A successful response will look like this:

{
  "status": "success",
  "data": {
    "operationId": "operation-uuid"
  }
}

and your newly updated property list will look like this:

Updating NFT Card Level

The section above can also be used to guide you through updating the card level over time. In fact, you can pass the update value for the operation property and if the index/tokenId matches your change will be reflected. You will still need to publish those changes, which is outlined below.

Publishing Properties Onchain

When you’re ready to publish your property list item changes, a single API call will push staged items and make them available for onchain consumption.

const appId = "your-app-id";
const propListId = "your-property-list-id";
const accessToken = "your-access-token";

const publishPropertyListItems = async () => {
  const response = await fetch(
    `https://sandbox.api.o2-oracle.io/apps/${appId}/propertylists/${propListId}/publish`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${accessToken}`,
      },
    }
  );
  console.log(await response.json());
};

publishPropertyListItems();

A successful response will look like this:

{
  "id": "uuid",
  "entity_id": "entity-uuid",
  "entity_type": "property_list",
  "operation_type": "publish",
  "status": "pending"
}

And your property list dashboard will look like this:

Wrapping Up

Here’s a summary of the full flow:

  1. Authenticate and get your access token and organization ID.
  2. Use those to get your app ID.
  3. Use your app ID to get your property list ID.
  4. Add or update property list items using the API.
  5. Publish your changes onchain.

Now you’re ready to push your offchain data onchain and make it available for rules evaluations! The next step from here is to actually leverage this onchain data in a rule, which is covered in the next guide. See you there!