NFTs on Steem Engine: A Technical Overview

in #steem-eng5 years ago (edited)

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!

Sort:  

Holy shit.
If we will see Art and real estate linked to non-fungible tokens in the future, this will change everything. People have no idea.

I agree! NFTs are going to be the next big wave in the blockchain technology revolution. I've seen at least one company in Japan that is looking into setting up a legal framework for tokenizing real estate. The idea they have is crowdfunding the purchase of a large apartment building, with tokens to represent ownership shares of the building. Owning the tokens would entitle you to a proportional share of rental income from the building's tenants.

That's freaking nuts! I love this.
Looking forward to investing in theese kind of NFTs.

You are truly building something here. It's super interesting to read the posts from the team, makes me wanna learn phyton.
Amazing to see what is possible.
Greets :)

Thanks for your support! Glad you enjoy our posts. Python's not too hard to learn if you want to give it a try. :-)

I have started a course already, let's see how far I get ;)

We saw with cryptokitties that this type of thing could be popular. Hopefully things catch on and more use-cases will follow

@cryptomancer, First of all congratulations for being a part of this huge upcoming change.

For sure this was and is not a easy job because in a way you are creating a whole new world and we can imagine or may be not, how much efforts you've put into this work.

Hope that this will going to turnout into something huge and will bring huge success to this project and to you.

Good wishes from my side and stay blessed.

Posted using Partiko Android

So not sure how the 100 eng fee is working. We want to put up 100 different items are players are using in SteemQuest, do we have to pay 100 eng for each item ??
And with our chestbot we need the intrinsic value out of the gate.

No. You could have one NFT and use data properties to specify what type of item it is. So you could call your token QUEST or some other name, then in the properties when you issue have a property called name which specifies what the name of the item is. To save money on additional properties, you could have a custom ID and keep track of items in your own DB.

{ 
  "contractName": "nft",
  "contractAction": "issue",
  "contractPayload": {
      "symbol": "QUEST",
      "to": "playeraccount",
      "feeSymbol": "SSC",
      "properties": {
          "name": "item",
          "itemId": 2
      }
  }
}

You would then reference itemId in your own table when dealing with the NFT to determine what it corresponds to. If managing your own database for items is not ideal, just pay to have additional fields for your token at 100 ENG a piece. So, you could easily have an NFT with 10 additional fields for info at a one-off cost of 1000 ENG.

No the Databse is Ideal for me. Working on that right now.
So if I issue say a Quest Token with name Gobln Sword and ID#201
The player issued the token see’s just the name in the wallet ??
I would like them to see the image.

Thanks for the response it made things so much clearer for me

Thank you for the detailed guide.
This is exciting and a perfect use case for our game. We will work on implementing it.

You're quite welcome, and I hope NFTs will be useful for your game. I checked out your blog; the game looks fun and I like the concept of using bread as a currency. It's a really fresh idea, if you'll pardon the pun!

I appreciate the explanation and it definitely gives me a better understanding what an NFT is, now I'm just thinking about all the different ways someone my implement them and why that might matter to me.

This is amazing!

I'm witnessing the future right here.