SFTs: Flow and Smart Contracts
Last updated
Last updated
To highlight the benefits of implementing the SFT standard into Web3, we have built a scenario of an RPG mini game. The logic of the game is that the player will have to fight different mystic creatures in order to advance, but also he could farm in order to mint some of the resources. Minting new items will be possible using at least one of the following methods: acquisition, crafting and level-up. Providing functionality to each of these three methods will be captured inside a single smart contract using three different public functions.
Web3 games need to host their items, characters and all kinds of assets that are owned by the player. Here are some smart contracts designed for specific games as their dynamics and needs are different:
• MMO Strategy - resources ( gold, silver, wood ) and buildings ( town hall level 9, tower of fire level 3, storage level 5 )
• RPG - resources (gold, stamina, health) and items (wood sword level 2, steel armor plate level 4)
• Card Game - resources (gold) and cards (every single card is another type of SFT with its attack, health, mana cost and other stats)
We have designed our game to contain SFTs divided into two categories: resources and items. We have considered resources the intermediaries to purchasing or crafting, while items can be equipped and used in order to advance into the game's plot. Each item has power attributes depending on the level and the base material which it is built of.
As we have mentioned before, Web3 gaming raises the need of handling the entire process in a decentralized, transparent and secure way. Creating the prerequisites for this fundamental need implies deploying smart contracts directly on the blockchain, and by this allowing the player to consult the smart contract / contracts which represent the basis of the game's functionality. Because of the fact that we know beforehand the whole flow of the game we are developing, we have only built a single smart contract which allows us to handle all the use cases. Next, we will breakdown the game's flow and the clarity functions we are using to operate the player's possible actions, described before.
The clarity function that represents the ground for each of the three possible functionalities is the burn one. Its structure is the following:
The burn function is responsible for burning a given amount of a token from the sender address. Firstly, it creates a local variable called sender-balance
which represents the balance of the certain token for the address which initiates the transfer. After that, it assures that the sender is valid and the amount of the sent token owned by the sender is enough to complete the burn. As it can be observed, it calls another function named tag-nft-token-id
. It is structured like this:
This function firstly checks if the owner has a certain type of token semi-fungible-token-id
, and attempts to burn it for the given address. After that, it mints the token for the owner address. Going back to the transfer function, after handling the burn-mint phase, it updates the balances of the given token for each of the sender and the recipient. If none of the conditionals negatively influence the execution thread, the transfer function finally returns an (ok true)
and prints a brief confirmation message of the transaction that has just been initiated and sent to the blockchain.
map-set(we define them using a single SC bc we know beforehand, transparent for the players),
Here begins the stage where we establish the rules of the game. For every asset the player wants to obtain (by acquisition, crafting or level-up), he will need a series of required resources. These can be either resources or items. For every single token that needs to be minted, we will store the tokens required in exchange using a dictionary for each of the three possible operations. All of these dictionaries will be found inside one single smart contract which will be deployed on-chain. Here's an example:
After on-chain storing in a transparent way the rules of the game, we will want to create queries onto the already set needed tokens in order to perform every single in-game operation. These queries will be executed using map-get method inside a read-only function, like that:
We have created a read-only function for each use case the player can fit in. Next, we will split the game's thread in three scenarios.
As we have set before all the dictionaries containing the requirements for minting new assets, along with the read-only functions to create queries onto them, we will need three functions, one for each use case.
The Acquisition represents the rawest way a player can mint a new asset. By acquisitioning new items, the player will only burn resources, and not other owned items. For a balanced gameplay, only some of the items could be acquisitioned and the player will have to mix the other two use cases in order to successfully proceed. The function which will handle the Acquisition action looks like this:
This function creates a local variable containing the resources needed for buying a new token and one for verifying if the tx-sender
owns enough of the needed resources using is-owned-needed
private function. After that, it ensures the token for which we perform the query has set resources inside the corresponding dictionary and the tx-sender owns enough of the needed tokens. After that it calls the burn-wrapper
public function which is responsible for burning the given amount of the needed tokens from the sender.
Finally, if the function's execution thread is not interrupted by the previous conditionals, it mints one new token.
The Crafting represents the the way a player can construct a new asset. By crafting new items, the player will burn resources and items. The function which will handle the Crafting action looks like this:
This function follows the flow of the Acquisition one, because even if the in-game ways of obtaining a wanted token are very different, inside the smart contract they are almost the same.
The Level-Up represents the the way a player can upgrade an already owned asset. By upgrading existent items, the player will burn resources and old items in order to obtain a new token. The function which hadles the Level-Up action looks like this:
This function follows the flow of the Acquisition and Crafting ones.
In order to enable the User Interface and render the assets images and attributes to the Front End we have to set, and then to be able to get one given token's URI. To allow this, we have created a token-uri
dictionary. We will set for each token-id
the corresponding JSON URL containing the token's attributes we have previously stored using a decentralized storage, in our case Pinata.