NFTs on Steem Engine: A Technical Overview

Steem Engine Logo.JPG

Change is coming. Radical, next level, out of this world, mind blowing change. As the developer in charge of building out back-end support for NFTs on Steem Engine, I'm incredibly excited to be one of the agents of this change. I've been busily churning out code for the past couple months, getting everything ready. Now it's finally time to reveal some of the details many of you have been waiting for!

This post covers things from a technical perspective, so will be most useful to programmers and people looking to take advantage of NFTs in their applications.

TL;DR: everything you need to know to work with Steem Engine NFTs is documented here:

NFT Reference Manual
NFT Market Reference Manual

NFT... what is it and why should I care?

NFT stands for Non-Fungible Token. It's a whole new type of token, very different from, say, Bitcoin or Ether or Steem, or anything currently on Steem Engine (those are technically known as fungible tokens). Unlike regular cryptocurrencies, NFTs allow each individual token to be unique. This is accomplished by means of special data properties that are attached to each token. The values of the data properties can vary from token to token, making each one different from all the others.

Splinterlands cards are a perfect example of an NFT. The data properties for Splinterlands cards are the card type, rarity, level, edition (Alpha, Beta, Promo, Reward, or Untamed), and whether the card is gold foil or not. If I want to sell one of my cards, if matters very much if I'm selling a mundane common or a much sought after legendary card. The details of the data properties distinguish the cards from each other in a big way.

NFTs are a great way to manage game assets, but that's just the tip of the iceberg. Imagine using NFTs to put physical, real-world assets on the blockchain. You could have an NFT that represents a property deed for real estate, or ownership of fine artwork. Investments that are normally illiquid and difficult to trade make perfect candidates for NFTs. Once digitized in such a way, they can be easily traded on Steem Engine's upcoming NFT marketplace (think a generalized version of the popular PeakMonsters market for Splinterlands).

The sky is the limit really, NFTs are still in their infancy and companies are just starting to explore their many potential uses.

So how do NFTs work on Steem Engine?

Steem Engine is a smart contracts platform. Smart contracts are basically pieces of code, small computer programs, that get executed by the blockchain in response to certain kinds of transactions. Everything you do on Steem Engine, from transferring tokens to placing market orders, is actually handled by smart contracts behind the scenes.

To interact with a smart contract, you post a custom json transaction on the Steem blockchain. The Steem Engine node software detects the transaction, parses its contents, and triggers an action in the relevant smart contract.

Each smart contract exposes a range of actions to the public, a type of API for providing some service. For example, the tokens smart contract provides actions such as transfer, stake, delegate, issue, etc. Similarly, there is an nft smart contract that provides analogous actions for NFTs.

All I have to do to use smart contracts is post custom json?

That's right! This means you can call smart contract actions from pretty much any programming language. Python and Javascript are popular choices.

You can even broadcast a custom json transaction directly from the SteemConnect web site. Go to https://v2.steemconnect.com/sign/ and select the Custom Json operation.

Most basic operations with NFTs (such as creating new ones, transferring them, trading them, and examining data properties) will be possible through the Steem Engine web site for non-technical users. However some programming skill will be required for more complex issuance & management mechanisms.

Can I go start playing with NFTs right now?

NFT support has not yet been enabled on the Steem Engine mainnet, however they are fully functional on the testnet so developers can try them out there first.

The Steem Engine testnet web site is: https://qa.steem-engine.com/

Keep in mind this web site is experimental and not all features may be working properly at any given time.

To do anything on the testnet you will need to get some SSC (the testnet equivalent of ENG). SSC is just a play token for testing, it has no actual worth.

To build a planet

The comprehensive NFT reference manual details all the actions provided for NFTs and how to use them. You can go read it at your leisure. I'm not going to rehash all that documentation here, but I do want to provide a short quickstart example of how to make a new NFT.

Let's say I developed a nifty space exploration game that allows players to discover new planets. I want my players to be able to name their planets and trade them with each other. Sounds like a perfect job for NFTs!

Let's make a new NFT called PLANET on the Steem Engine testnet. We want to support the following features:

  1. A planet has a location (x, y coordinates)
  2. A planet has a name
  3. Players should be able to rename planets

The first step is to create the PLANET NFT. We do this by broadcasting custom json for the nft smart contract's create action (you will be able to do this directly through the Steem Engine web site as well).

One easy way to do this is by using Python with the Beem library for working with Steem. Here's a snippet of Beem-based Python code for broadcasting the create action for our new NFT:

stm = Steem()
set_shared_steem_instance(stm)
stm.wallet.unlock("my password")

src = "my Steem account name"
tx = TransactionBuilder()
op = operations.Custom_json(**{"required_auths": [ src ],
                    "required_posting_auths": [],
                    "id": "ssc-testnet1",
                    "json": {
                       "contractName": "nft",
                       "contractAction": "create",
                       "contractPayload": {
                          "symbol": "PLANET",
                          "name": "Galactic Planets",
                          "url": "https://mynft.com",
                          "maxSupply": "10000"
                       }
                    } })
tx.appendOps(op)
tx.appendSigner(src, 'active')

print("broadcasting custom json transaction for", src, ":", tx)
try:
    tx.sign()
    tx.broadcast()
    print("SUCCESS")
except Exception as e:
    print("FAILED:", e)

A few things to notice about this:

  1. The create action requires active key authority, so we sign the transaction with our active key instead of posting key.
  2. The custom json ID is ssc-testnet1, because we are working on the Steem Engine testnet rather than the mainnet.
  3. There are various parameters for the create action, here we just give a simple example. Again, consult the NFT reference manual for full details.
  4. Creating an NFT requires a 100 SSC (or 100 ENG for the mainnet) fee, which is paid automatically when you call the create action. If your account doesn't have enough to pay the fee, the action will fail.

Adding data properties

Okay, we've got our PLANET NFT. But as it stands, there's not much we can do with it yet. Now we need to give it data properties to support our desired features.

It's important to note that an NFT can have as many data properties as you need, but only the first 3 are free. You'll have to pay a 100 SSC (or 100 ENG on the mainnet) fee for every additional data property beyond the third. Fortunately we only need 3 data properties for PLANET, so we won't have to pay any more fees.

Let's add the following data properties: x, y, and name

We will broadcast a separate custom json transaction for each data property we want to add (I'm not going to bother reproducing the Python program again here, you get the idea). With your active key, the transactions are:

{ 
  "contractName": "nft",
  "contractAction": "addProperty",
  "contractPayload": {
      "symbol": "PLANET",
      "name": "x",
      "type": "number",
      "isReadOnly": true
  }
}

{ 
  "contractName": "nft",
  "contractAction": "addProperty",
  "contractPayload": {
      "symbol": "PLANET",
      "name": "y",
      "type": "number",
      "isReadOnly": true
  }
}

{ 
  "contractName": "nft",
  "contractAction": "addProperty",
  "contractPayload": {
      "symbol": "PLANET",
      "name": "name",
      "type": "string"
  }
}

Note that x and y are numbers, and we indicate they should be read-only (a planet's location can only be set once, it never changes). Whereas name is a string which the player will be able to edit.

Issuing tokens

In my space game, when players discover a new planet, the game has to issue them a PLANET token to represent that discovery. Issuing new tokens is simply a matter of broadcasting yet another custom json, specifying the data properties to assign to the new token and which account it should go to.

Note that by default, only the Steem account that created the NFT with the create action is able to issue new tokens. However, there is a way you can specify a list of accounts to be granted issuance authority, as well as separate lists of accounts that are authorized to edit data properties on issued tokens. Go read the NFT reference manual for more details on that.

Also, there is a small fee per token issued, which varies according to the number of data properties an NFT has. For a token with 3 data properties, like our PLANET, the fee will be 0.004 ENG per token. So the game owner needs to make sure the game account stays stocked with enough ENG to cover expected token issuance.

Here is the custom json for issuing a PLANET token with a random location and no default name set (this also requires active key authority):

{ 
  "contractName": "nft",
  "contractAction": "issue",
  "contractPayload": {
      "symbol": "PLANET",
      "to": "playeraccount",
      "feeSymbol": "SSC",
      "properties": {
          "x": 57,
          "y": -489
      }
  }
}

Note the fee symbol is set to SSC for the testnet. You would use ENG for the mainnet. It's also possible to pay issuance fees with PAL, and potentially other tokens in the future.

What's in a name

Once players have found a planet, they'll want to give it a name. Players can't edit NFT data properties directly. Instead, the space game should allow them to type in a name and then issue the corresponding custom json command on the player's behalf.

Here's the custom json for editing the name data property, which by default can only be done by the same account that created the NFT. Unlike our earlier actions, this can be done using only the posting key:

{ 
  "contractName": "nft",
  "contractAction": "setProperties",
  "contractPayload": {
      "symbol": "PLANET",
      "nfts": [
        { "id":"1284", "properties": {
            "name": "Coruscant"
           }
        }
      ]
  }
}

The id field identifies which particular token to edit (in this case token #1284). The space game itself will need to keep track of which token IDs belong to which players. Once PLANET tokens are issued, the JSON RPC server query API can be used to look up this information from the blockchain database. How to do so is beyond the scope of this tutorial. I may write a follow-up post about queries at a later date.

Where to go from here?

We've barely scratched the surface of NFTs in this post. They have some other useful features, such as delegation and the ability to lock regular Steem Engine tokens within an NFT to give the NFT built-in intrinsic value.

A more fleshed out example of a Splinterlands style NFT pack issuance mechanism is available here:

Critter Manager smart contract source code

Everything done in the critter manager contract can be done just as well from Python or Javascript. It's worth repeating that all NFT interactions can be boiled down to simply broadcasting the appropriate custom json commands. It demonstrates the following features:

  • allow NFT owner to configure different editions (think Splinterlands ALPHA, BETA, and UNTAMED)
  • programmatically create the CRITTER NFT through a contract action
  • open a "pack" to generate critters by randomly varying properties such as critter type, rarity, and whether the critter is a gold foil or not.
  • allow different pack tokens for each edition - the contract gives users a way to exchange pack tokens for newly issued critters
  • update data properties - a user can call a contract action to set a name for critters that he/she owns

The CRITTER token is live on the testnet, as is the critter manager contract, so you can try it out by hatching some CRITTERs with SSC right now.

Give me more documentation!

If this post has whetted your appetite for NFTs and you're chomping at the bit for more, here's links to all the official and quite exhaustive documentation:

NFT Reference Manual
NFT Market Reference Manual
Steem Smart Contracts Wiki

If you have questions or need help getting started, visit the Steem Engine Discord and ask for @cryptomancer in the #developers channel.

I'm greatly looking forward to seeing all the creative ways that NFTs get put to use. Keep calm and Steem on!

H2
H3
H4
3 columns
2 columns
1 column
36 Comments
Ecency