Lyra tokens can be created as either indistinguishable, fungible or unique, non-fungible tokens (NFT). In fact, there are use cases for both in most applications, with transition from fungible to non-fungible at the time of redemption. Example: fungible reward tokens (as accumulated loyalty reward points) and non-fungible discount tokens that contain unique discount codes or gift (as loyalty reward redemption mechanism).
There is another big nische for NFT - collectibles. Unlike discount NFT mentioned above, collectibles do not carry any specific function, but can be used as awards, memorabilia, or simply rare digital collectible artifacts.
Each instance of Lyra NFT has unique properties like SerialNumber (for collectibles) or RedemptionCode (for discount code and coupons). Collectible NFT instance has a unique SerialNumber which distinguishes between the instances of the same NFT type and make each one a unique artifact.
The beauty of Lyra NFT is that it can be created and distributed by any user, not just by Lyra team or third party developers. It does not require any programming.
There are three basic operations that can be performed on Lyra NFT: genesis, issuing, and transfer. There are more operations associated with trading, but they are not covered here as Lyra DEX is still in development.
Every NFT starts with genesis of its type by the owner. Then, the owner can generate (issue) multiple instances of this token type (up to the maximum defined by the owner in NFT genesis block), and send those instances to other users. The recipients of the NFT instances can also transfer them to other account.
CLI wallet command: createnft
New NFT type must be generated in the same way a fungible token is generated, using the same TokenGenesisBlock block type. The only differences are IsNonFungible is set to True, ContractType is set to Collectible. Icon and Image may contain a URL to the token icon or image. There are also Owner, Address, and Tag properties that can be set by the owner. These properties are not unique per NFT instance though as they are assigned to the entire type.
For Collectible NFT, Precision must be set to 0 as its balance basically becomes its quantity which must be an integer number.
CLI wallet command: issuenft
The owner of the NFT genesis block can generate (issue) an initial instance of the NFT token and send it to a recipient'a account. The issuing account must be the same as the account that originally generated the TokenGenesisBlock. When a new NFT instance is issued, it is assigned the Denomination, SerialNumber, or/and RedemptionCode. The new object of type NonFungibleToken is created and assigned to the NonFungibleToken field of the SendTransferBlock or ExecuteTradeBlock (currently only supported for LoyalShopper discount NFT). The properties of the NonFungibleToken object are set as the following:
TokenCode - the full token name including domain name and ticker; for example: Lyra/MainetLaunch. ExpirationDate - optional.
Denomination - any amount not to exceed the remaining balance of the token type on the token genesis account.
RedemptionCode - encrypted by Diffie Helman using sender's private key and recipient's public key
Denomination - 1 (in this case, denomination indicates quantity; only 1 NFT instance per block can be issued or/and sent; however, a single account can contain multiple instances, which would be reflected by the balance of a particular token type).
SerialNumber - a unique number that identifies the NFT instance. Typically, serial numbers are incremented integers, but we don’t enforce it (which can be revised in the future), so currently the only rule is uniqueness.
CLI wallet command: sendnft
This is basically the ownership transfer of an already issued NFT instance to another owner. It is not necessary for RedeemedDiscount NFT, at least not before the reward token marketplace is operational. It is more useful for collectibles so they could be traded.
NFT transfer works by creating a SendTransferBlock or ExecuteTradeBlock that contains a NonFungibleToken object - identical to the initial instance. The recipient creates a ReceiveTransferBlock with a NonFungibleToken object, also identical to the initially issued instance. The process is similar to initial NFT instance issuing and transfer, with some limitations:
The values of TokenCode, SerialNumber, Denomination, and ExpirationDate fields must remain the same as in the original instance, in both SendTransfer and ReceiveTransfer blocks.
The wallet, when displaying NFT tokens, ensures that it displays only NFT instances that have been received on the account, and ignores (hides) the NFT instances that have been transferred to another account (although their records can be still stored on the account blockchain). So basically a wallet displays NFT instances (NonFungibleToken objects) from ReceiveTransfer blocks, and only if they do not have corresponding SendTransfer or ExecuteTrade blocks.
Only one account holder can claim the ownership of the NFT at the same time - the one that has the unspent ReceiveTransfer transfer block that contains the verifiable instance of NonFungibleToken. Unspent ReceiveTransfer block with NonFungibleToken means that there is no corresponding SendTransfer block with the same token instance (i.e. serial number) from the same account with higher block index.
CLI wallet command: nft
nft command shows the list of all NFT instances (both collectibles and discount codes) owned by the account. Note that if collectible NFT instance has been transferred to a different account it will not be displayed since the account does not own it anymore.