Create Publication

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Solution Thumbnail

AlgoRealm, a NFT Royalty Game

Overview

NFTs are gaining adoption in blockchain for different use cases: digital artwork, music, gaming, etc. Generally NFTs are used as tools to manage provable intellectual property rights over unique digital creations by their authors or as a tool to manage provable property rights over digital representations of unique assets and collectables.

While the community’s debate about NFTs is very animated, two topics get the most attention:

  1. How to store NFT-related data off-chain
  2. How to manage NFT royalties

Since blockchain is a good technology to ensure decentralized, tamper-proof digital data ownership but not decentralized, digital data storage, the first topic should be addressed with a systematic approach, because its implications are wider than the simple NFT domain and may involve other technologies such as IPFS.

This solution, on the other hand, will focus on the second question: addressing how to manage NFT royalties. We will use an on-chain game example: AlgoRealm.

AlgoRealm

AlgoRealm is a pretty simple NFT game.

The Algorand Realm is ruled by two Majesties:

  1. The Randomic Majesty of Algorand, who posses the Crown of Entropy NFT.
  2. The Verifiable Majesty of Algorand, who posses the Sceptre of Proof NFT.

Anyone can claim the titles of Majesty of Algorand by donating some ALGOs to the Rewards Pool. The more generous the donation, the harder it is to be dethroned: whoever donates more than the current Majesty claims the title and the related NFT artifact.

Although the main purpose of AlgoRealm is not to manage royalties, its working principles can be generalised and adopted as boilerplate for the development of an interface for an NFT royalty ASA, that responds to the following question:

How do we implement a royalties schema over a Non-Fungible ASA so that its creator can benefit from future transactions involving it?

Algorand Standard Asset is a great protocol feature that enables seamless tokenization of any kind of asset, NFTs being one of them. This solution aims to take it a step further, by proposing an extension of the NFT ASA properties in order to bind the NFT to on-chain royalties through the combination of other protocol features: Algorand Smart Contracts and Atomic Transfers.

There could be several NFT royalty policies, depending on the creators requirements, such as fixed commission to creators for each transaction involving their NFTs or variable commission to creators based on the NFTs exchange price.

Since AlgoRealm is just a simple NFT game, the royalties over its NFTs are collected by the Rewards Pool, representing donations that will be redistributed to the whole ecosystem by the consensus protocol directly.

In this specific case the donation coincides with the NFT price itself and its transferability is closely tied to royalty payments: the royalties are not collected on NFTs transfer but just on NFT claiming.

So how does the combination of ASA, ASC1 and AT enable royalties over AlgoRealm’s NFTs?

Solution Architecture

AlgoRealm NFT royalties, paid to the Rewards Pool, are managed by an orchestration of Algorand Standard Assets, Algorand Smart Contracts and Atomic Transfers. The goal is binding ASA’s manager addresses to a combination of Stateless and Stateful Smart Contracts that will enforce the royalty policy over the game’s NFTs.

  1. Algorand Standard Asset: implements AlgoRealm’s artifacts NFTs, controlled by the ASC1 through the ASA clawback address.
  2. Atomic Transfers: implements groups of transactions that force the simultaneous interaction between the AlgoRealm’s Stateful and Stateless components (as explained in this prerequisite article).
  3. Stateful Algorand Smart Contract: implements AlgoRealm Application that handles ASC1 global state which tracks the donations’ amounts and current Majesties’ nicknames.
  4. Stateless Algorand Smart Contract: implements the AlgoRealm Law as a Contract Account that approves NFTs clawback transactions according to royalties policy.

The dependencies between Algorand features imply a specific deployment sequence for the required components:

  1. Stateful Application deployment
  2. NFTs creation
  3. Stateless Contract Account deployment
  4. NFTs configuration
  5. Stateful Application configuration

Stateful Application deployment

The main purpose of the Stateful component is to read and write permanent on-chain information, according to predefined TEAL logic branches. AlgoRealm Stateful components makes use of the following variables:

Name Domain Type
AlgoRealmLaw Global ByteSlice
CrownOfEntropyDonation Global UInt
RandomicMajestyOfAlgorand Global ByteSlice
SceptreOfProofDonation Global UInt
VerifiableMajestyOfAlgorand Global ByteSlice

Since AlgoRealm state space does not involve Accounts’ Local State, the application does not require opt-in by the users.

Stateful Applications are composed by two distinct TEAL programs:

  1. Approval Program
  2. Clear Program

Their roles are described in the lifecycle of a Stateful Smart Contract.

Clear Program

AlgoRealm Clear Program will simply approve any clear call from the users to remove the application from their accounts
balance.

#pragma version 2
int 1

Approval Program

AlgoRealm approval program lets users interact with the Stateful ASC1 in two ways, handled by distinct branches of TEAL logic:

  1. Algorand Realm creation
  2. Algorand Realm actions

#pragma version 2
txn ApplicationID
int 0
==
bnz algorealm_creation
txn OnCompletion
int NoOp
==
bnz algorealm
int 0
return

Application Create

On application create transaction both Algorand Realm Majesties titles and donations’ amounts are initialized:

algorealm_creation:
byte "RandomicMajestyOfAlgorand"
byte "Silvio"
app_global_put
byte "VerifiableMajestyOfAlgorand"
byte "Silvio"
app_global_put
byte "CrownOfEntropyDonation"
int 0
app_global_put
byte "SceptreOfProofDonation"
int 0
app_global_put
int 1
return
b end_algorealm

Application Calls

There are two different actions corresponding to application call transactions:

  1. Algorand Realm Law promulgation
  2. Algorand Realm Majesties titles claim

algorealm:
global GroupSize
int 1
==
bnz algorealm_law
global GroupSize
int 3
==
bnz algorealm_claims
int 0
return

Algorand Realm Law is the Stateless ASC1 that regulates NFTs transferability. The alorealm_law branch guarantees that law’s promulgation can occur only once and cannot be changed in the future (even by the application creator):

algorealm_law:
int 0
byte "AlgoRealmLaw"
app_global_get_ex
store 0
store 1
load 0
bnz promulgate_law_failure
byte "AlgoRealmLaw"
txna ApplicationArgs 0
app_global_put
b promulgate_law
promulgate_law_failure:
int 0
return
b end_algorealm
promulgate_law:
int 1
return
b end_algorealm

The algorealm_claims branch asserts that Majesties’ titles claims follow the NFTs royalties policy. Claims of Algorand Realm Majesties titles are executed as an Atomic Transfer that:

  1. Calls the AlgoRealm Application
  2. Passes 2 arguments to the Application: the claiming title (Randomic Majesty or Verifiable Majesty) and the next Majesty nickname
  3. Transfers the corresponding NFT ASA (Crown or Sceptre) from the current owner to the claiming users

algorealm_claims:
gtxn 0 TypeEnum
int appl
==
gtxn 0 NumAppArgs
int 2
==
&&
gtxn 1 TypeEnum
int pay
==
&&
gtxn 2 TypeEnum
int axfer
==
&&
gtxn 2 Sender
byte "AlgoRealmLaw"
app_global_get
==
&&
bnz claims
int 0
return
b end_algorealm

The first argument submitted with the application call transaction determines which NFT will be claimed:

claims:
gtxna 0 ApplicationArgs 0
byte "Crown"
==
bnz claim_crown
gtxna 0 ApplicationArgs 0
byte "Sceptre"
==
bnz claim_sceptre
int 0
return
b end_algorealm

Passing Crown as first argument of the application call the user will claim the Randomic Majesty title if and only if the donation to the Rewards Pool is greater than the last one. In case of successful donation the CrownOfEntropyDonation and RandomicMajestyOfAlgorand global variables will be updated with the new amount and the user’s nickname passed as second argument of the application call transaction.

claim_crown:
gtxn 1 Amount
byte "CrownOfEntropyDonation"
app_global_get
>
bnz randomic_majesty
int 0
return
b end_algorealm
randomic_majesty:
byte "RandomicMajestyOfAlgorand"
gtxna 0 ApplicationArgs 1
app_global_put
byte "CrownOfEntropyDonation"
gtxn 1 Amount
app_global_put
int 1
return
b end_algorealm

The same logic applies to the Verifiable Majesty title claims if Sceptre is passed as first argument of the application call:

claim_sceptre:
gtxn 1 Amount
byte "SceptreOfProofDonation"
app_global_get
>
bnz verifiable_majesty
int 0
return
b end_algorealm
verifiable_majesty:
byte "VerifiableMajestyOfAlgorand"
gtxna 0 ApplicationArgs 1
app_global_put
byte "SceptreOfProofDonation"
gtxn 1 Amount
app_global_put
int 1
return
end_algorealm:

AlgoRealm application has been deployed as follow:

$ ./goal app create --creator CREATOR_ADDRESS --approval-prog algorealm_approval.teal --clear-prog algorealm_clear.teal --global-byteslices 3 --global-ints 2 --local-byteslices 0 --local-ints 0

NFTs creation

Both the Crown of Entropy NFT and Sceptre of Proof NFT are implemented as unique and indivisible ASA, that means their total supply is set to 1 and their decimals are set to 0, asserting that just one Crown and one Sceptre will ever exist in the Algorand Realm.

$ ./goal asset create --creator CREATOR_ADDRESS --name "Crown of Entropy" --unitname "CROWN" --total 1 --decimals 0

$ ./goal asset create --creator CREATOR_ADDRESS --name "Sceptre of Proof" --unitname "SCEPTRE" --total 1 --decimals 0

Once both the NFTs ASA are issued on-chain their Asset IDs are known: this information will be included into the Stateless TEAL source code.

Stateless Contract Account deployment

Now that Algorand Realm informations are defined:

  1. AlgoRealm Application ID
  2. Rewards Pool Address
  3. Crown of Entropy Asset ID
  4. Sceptre of Proof Asset ID

AlgoRealm Law TEAL source code can be parametrised to generate the Contract Account. The AlgoRealm Law approves Majesties’ titles claims submitted as Atomic Transfer that:

  1. Calls the AlgoRealm Application
  2. Donates ALGO to the Rewards Pool
  3. Claims the Crown NFT or the Sceptre NFT

From the same Account.

#pragma version 2
global GroupSize
int 3
==
gtxn 0 TypeEnum
int appl
==
gtxn 0 ApplicationID
int 137491307
==
&&
&&
gtxn 1 TypeEnum
int pay
==
gtxn 1 Sender
gtxn 0 Sender
==
&&
gtxn 1 Receiver
addr 737777777777777777777777777777777777777777777777777UFEJ2CI
==
&&
&&
gtxn 2 TypeEnum
int axfer
==
gtxn 2 AssetReceiver
gtxn 1 Sender
==
&&
gtxn 2 XferAsset
int 137493252
==
gtxn 2 XferAsset
int 137494385
==
||
&&
gtxn 2 AssetAmount
int 1
==
&&
gtxn 2 Fee
int 1000
<=
&&
gtxn 2 AssetCloseTo
global ZeroAddress
==
&&
gtxn 2 RekeyTo
global ZeroAddress
==
&&
&&

The purpose of AlgoRealm Law Contract Account is acting as Clawback Address for both NFTs artefacts. Delegating the Clawback power over the NFTs to the AlgoRealm Law Contract Account let users revoke the Crown or the Sceptre from anybody else, as long as the corresponding donation is grater than the existing one.

Compiling the algorealm_law.teal source code we obtain the Clawback Address with which both NFTs will be updated.

$ ./goal clerk compile algorealm_law.teal

algorealm_law.teal: ALGOREALM_LAW_ADDRESS

NFTs configuration

What really extends AlgoRealm’s NFTs as royalty-based Non-Fungible ASA is that the NFTs’ Clawback Address is managed by the combination of AlgoRealm Stateful Application and AlgoRealm Law Stateless Contract Account. NFTs’ role-based management configuration must be executed after both Steteless and Stateful components have been deployed. Since AlgoRealm’s NFTs should be controlled uniquely by the ASC1, with the guarantee that nobody will ever be able to configure NFTs’ management again nor freeze them, the NFTs’ configuration transactions will:

  1. Set NFTs’ Clawback Address as AlgoRealm Law
  2. Delete NFTs’ Freeze Address
  3. Delete NFTs’ Manager Address

$ ./goal asset config --assetid CROWN_ASSET_ID --manager CREATOR_ADDRESS --new-clawback ALGOREALM_LAW_ADDRESS --new-freezer "" --new-manager ""

$ ./goal asset config --assetid SCEPTRE_ASSET_ID --manager CREATOR_ADDRESS --new-clawback ALGOREALM_LAW_ADDRESS --new-freezer "" --new-manager ""

At this point NFTs’ management configuration cannot be changed any more.

Stateful Application configuration

As last, deployment of the AlgoRealm Application is executed by the creator with the AlgoRealm Law Contract Address that handles NFTs’ Clawback Address. Once the Algorand Real Law has been promulgated it cannot be changed anymore.

$ ./goal app call --app-id ALGOREALM_APP_ID -f CREATOR_ADDRESS --app-arg "addr:ALGOREALM_LAW_ADDRESS"

Conclusions

This solution provides an example for the implementation of royalty policies embedded into the NFTs for those use-cases in which NFT’s creators want to apply royalties on future NFT’s transactions or exchange. Binding ASA management addresses, such as Clawback of Freeze, to a combination of Stateful and Stateless ASC1 is possible to create very expressive royalties policies over NFTs.

Claim the Crown or the Sceptre!

Follow AlgoRealm game instructions and claim the title of Randomic Majesty of Algorand or Verifiable Majesty of Algorand.