Read Time: 32 Mins

Fungible gets Non-Fungible Attributes.

Unleash Your Creativity to Earn Bitcoin and Ethereum.

To begin, let me emphasize that I am inherently a computer scientist and coder. This passion has been ingrained in me since my early years when my German neighbor gifted me a computer.

The world of programming has always captivated me. The sheer thrill of making computers obediently carry out my commands has been a source of exhilaration. Throughout my adult life, my primary focus has been within the AI domain, where I have tirelessly strived to push the boundaries of intelligence and automation in computing.

I have undertaken the development and launch of numerous iterations of AI systems, each specializing in various tasks such as data derivation, financial projections, targeted data sourcing and delivery, and comprehensive multi-agent processing analysis. This relentless pursuit has truly allowed me to push the envelope of AI from within for many years.

Naturally, my involvement in this field has also necessitated my familiarity with the world of cryptocurrencies. During the early days, when I required specific programs for my work in the White Hat community, I had to utilize Bitcoin as a currency rather than an investment vehicle. To provide some context on the timeline, I would convert Linden Dollars from Second Life into Bitcoin by using them as a fiat on-ramp via PayPal into Virwox. This process enabled me to purchase the necessary software using Bitcoin.

Being deeply entrenched in these two diverse sectors, I have inevitably paid close attention to the legal aspects surrounding cryptocurrencies over the years. I have observed the vague guidance provided by various authorities, the debates regarding centralized versus decentralized systems, the distinctions between security and utility tokens, as well as the differences between fungible and non-fungible tokens. Amidst these dichotomies, understanding why certain assets are classified as securities while others are not has proven to be a genuine challenge.

In order to truly comprehend the current situation and chart a path forward, we must delve deep into the intricacies. Only then can we navigate our way out of the complexities and open up the sector, liberating it from the speculative and legal entanglements that have plagued the realms of blockchain and cryptocurrency. It’s worth noting that as a British citizen, this issue does not directly impact me, as the industry and its populace in the United States are the ones being hindered. Nonetheless, I have offered these thoughts to encourage further contemplation on the crucial questions surrounding fungible and non-fungible tokens in the U.S.

Let’s examine the components that make up a security based on the well-established Howey test:

  1. Investment of money: This refers to the act of providing funds, capital, or any form of monetary contribution.

  2. Common enterprise: A common enterprise exists when multiple investors pool their resources or investments in pursuit of a shared objective. The success or failure of the enterprise depends on the collective efforts and actions of those involved.

  3. Expectation of profit derived from the efforts of others: This element signifies that investors anticipate earning a return on their investment, and this return is primarily dependent on the efforts, skills, or expertise of others. In other words, the investors rely on someone else, typically the issuer or a third party, to generate profits or enhance the value of their investment.

When evaluating different objects or offerings in financial terms, these three elements are applied to determine whether they meet the criteria of a security. By assessing if an investment involves the contribution of money, participation in a common enterprise, and an expectation of profits derived from the efforts of others, one can ascertain whether it qualifies as a security under the Howey test.

Object

Investment of money?

Common enterprise?

Expectation of profit?

Security?

Apple stock

yes

yes

yes

yes

Stamp

yes

no

no

no

Gift cards

yes

no

no

no

Bitcoin

yes

yes

yes

no

Ethereum

yes

yes

yes

no

ERC20 tokens

yes

yes*[1]

yes*[2]

no/yes*[3]

Pokemon cards / Beanie babies etc

yes

no

no

no

Fine art

yes

no

no

no

NFTs (Blockchain based art/music etc’)

yes

no

no

no

Cash (notes)

yes

yes

no

no

Cash (coins)

yes

yes

no

no

[1] The notion of a “common enterprise” assumes the existence of a structured enterprise. However, in the case of many “legitimate” protocols, decentralization is taken to such an extent that governance is fluid and determined by individuals who actively hold the tokens. These token holders participate in governance decisions or individuals who purchase tokens to vote on matters that directly affect them or align with their perspectives. In these scenarios, the concept of a centralized enterprise may not apply, as decision-making power and influence are distributed among token holders in a decentralized manner

[2] Many token purchases serve various purposes within digital ecosystems, such as enabling participation in governance mechanisms or facilitating transactions for goods and services. These purchases extend beyond mere speculation for profit-making purposes.

[3] Determining whether a fungible token is inherently a security is arguably a case-by-case assessment based on the specific facts and circumstances surrounding it. Each token should be evaluated independently to ascertain its classification as a security or otherwise.

The above chart demonstrates that applying the Howey test can provide clarity in distinguishing between securities and non-securities. If this were the extent of guidance and influence from oversight committees, there would be less confusion in the cryptocurrency world.

However, delving deeper into the intricacies of cryptocurrencies reveals a different perspective. Some cryptocurrencies originated as vehicles for crowdfunding, wherein investors contribute funds with the expectation of future value appreciation based on the promise of building a specific product or service. This scenario clearly aligns with the definition of an investment in a common enterprise. On the other hand, certain cryptocurrencies, commonly known as utility tokens, were created primarily as a means of payment for services within existing ecosystems. These utility tokens function similarly to digital gift cards, where the mechanism to redeem their face value already exists. In this case, there is no inherent common enterprise, as the token issuers do not hold jurisdiction over the token holders’ ability to profit.

The distinction between these two types of cryptocurrencies further highlights the complexities and nuances in classifying tokens as securities or non-securities. It underscores the need for a comprehensive understanding of the specific nature and purpose of each token to determine its regulatory status accurately.

Given that there is already an element of confusion as to what is or isn’t a security based on that single prong of the Howey test on issuance, it becomes even more confusing when you look at the same objects under the lens of potential profitability post issuance

How could it work when Howey is brought to bear on the same objects post-issuance in financial terms?

Object

Was there an investment of money?

Common enterprise?

Expectation of profit?

Could it be classed as a security now?

Apple stock

yes

yes

yes

yes

Stamp

yes

no

yes

yes

Gift cards

yes

no

no

no

Bitcoin

yes

yes

yes

yes*[4]

Ethereum

yes

yes*[5]

yes

yes & no

ERC20 tokens

yes

yes*[1]

yes*[2]

yes

Pokemon cards / Beanie babies etc

yes

no

yes

yes

Fine art

yes

no

yes

yes

NFTs (Blockchain based art/music etc’)

yes

no

yes

yes

Cash (notes)

yes

yes

yes

yes

Cash (coins)

ye

yes

yes

yes

[4] Bitcoin, arguably, relies on a core group of individuals who actively maintain its code. These individuals often receive financial support through grants from various entities. Interestingly, some of these entities also function as exchanges, actively promoting Bitcoin and directly selling it to consumers. It’s worth noting that these entities have a vested interest in Bitcoin, as they not only facilitate its trading but also have mining operations or investments in Bitcoin mining companies. This interconnectedness among code maintainers, sponsors, exchanges, and mining ventures showcases the intricate relationships within the Bitcoin ecosystem.

[5]

Arguably, there exists a group of core developers who play a crucial role in maintaining and advancing the Ethereum ecosystem. These developers are also involved in multiple capacities within the Ethereum landscape. They operate the foundation that actively promotes Ethereum and have direct interests in various protocols, projects, corporations, and entities that are built upon the Ethereum platform.

Examining the available information, one can observe that these individuals bear significant expectations in terms of their influence and impact. However, over time, as new waves of crypto enthusiasts enter the market, the focus on these individuals has gradually diminished. Similar to individuals purchasing XRP without necessarily being aware of its connection to Ripple, a similar trend can be observed today with Ethereum, the Ethereum Foundation, and notable figures like Vitalik Buterin and Joseph Lubin.

This evolving dynamic is a natural occurrence as the cryptocurrency market attracts a broader range of participants, each with their own level of awareness and understanding of the underlying associations and key figures within different crypto projects.

The chart doesn’t appear to change very much, except in the expectation of profit column, this is where it gets a bit fun. All 4 objects are classed as collectible and are liable to increase in value beyond their original price or redeemable value within the systems they were issued for. Millions of people worldwide collect objects with the intention of selling them for a greater amount than paid to some, as yet unknown, third party.

For example, stamp collectors (philatelists) intentionally purchase entire sheets of newly issued stamps, anticipating that they will become rare and therefore sellable at a premium in the future. Coin collectors are constantly searching for unique or old coins/notes that possess a value surpassing their face value, such as coins with minting errors or notes with specific serial numbers. Toy collectors acquire entire collections of specific toys, preserving them in mint condition within their original packaging, believing that these items will appreciate significantly over time.

These variations in the perception of potential profit and the legal classification of securities versus non-securities have led me to question the existing systems. Why does the system exhibit such inconsistencies? Why are certain objects designated as securities while others are not? Upon closer investigation, a common theme emerges—one that revolves around rarity, uniqueness, and collectibility.

The concepts of rarity, uniqueness, and collectibility appear to be fundamental factors influencing the distinction between securities and non-securities. This realization prompts further inquiry and exploration into the underlying mechanisms and motivations driving these distinctions within the regulatory framework.

Let’s look at some alternate commonalities between the objects we are reviewing:

Object

Are they created in great numbers?

Do they become rare over time?

Do they change in perceived value?

Are they individually unique?

Are they classed as securities?

Apple stock

yes

no

yes

no

yes

Stamp

yes

yes

yes

yes & no

no

Gift cards

yes

no

no

no

no

Bitcoin

yes

yes

yes

no

no

Ethereum

yes

yes

yes

no

Yes & no

ERC20 tokens

yes

yes & no

yes

no

yes

Pokemon cards / Beanie babies etc

yes

yes

yes & no

yes & no

no

Fine art

no

yes

yes

yes

no

NFTs (Blockchain based art/music etc’)

no

no

yes

yes

no

Cash (notes)

yes

yes

yes

yes

no

Cash (coins)

yes

yes

yes

yes & no

no

When examining the analysis, it becomes evident that the classification of an object as a security or not boils down to a fundamental question: Is the object I am purchasing unique enough to be considered collectible?

Various examples highlight the concept of rarity and its influence on value appreciation. Stamps become rarer as they are used or retained, increasing their value over time. Similarly, items like Pokémon cards and beanie babies gain rarity as they are played with or become scarce in circulation. Cash and coins also become rarer due to factors such as replacement or removal from circulation, increasing the value of those that remain. Fine art pieces inherently possess uniqueness and rarity, contributing to their expected appreciation over time. Even serial numbers on cash/notes can make them collectible and potentially exceed their initial value.

From this analysis, it can be argued that the primary criterion for determining whether an object is a security or not is its level of rarity or uniqueness. The potential for value appreciation from the day of creation or issuance seems to hold little significance in this regard.

An alternative term to describe a lack of uniqueness is “fungible.” When something is fungible, it means there are identical items that can be interchanged with one another. Cryptocurrencies, by their nature, are fungible as they consist of exact copies of code. To further explore this concept, we can draw comparisons among the previously discussed objects and identify meaningful connections.

Object

Are they created in great numbers?

Do they become rare over time?

Do they change in perceived value?

Are they individually unique?

Are they classed as securities?

Stamp

yes

yes

yes

yes & no

no

Ethereum

yes

yes

yes

no

no

ERC20 tokens

yes

yes & no

yes

no

yes

NFTs (Blockchain based art/music etc’)

no

no

yes

yes

no

Cash (notes)

yes

yes

yes

yes

no

The selection of the five objects mentioned above was deliberate and serves a purpose in highlighting certain aspects. Firstly, stamps share a similar function with Ethereum as they both act as payment mechanisms within their respective ecosystems. Ethereum serves as gas to pay for data deliveries, while stamps are used for postal deliveries. Furthermore, Ethereum not only functions as a payment mechanism but also forms the foundation for the entire ERC20 blockchain ecosystem, upon which other ERC20 platforms are built.

NFTs (Non-Fungible Tokens), on the other hand, are unique blockchain-based systems that are not classified as securities due to their rarity and uniqueness.

Cash, specifically banknotes, serves as a means of value exchange and possesses individual serial numbers that make each note unique.

It is important to bring ERC20 tokens into the discussion as they play a crucial role. Without them, the entire article would lose its relevance.

Among the five objects mentioned, only alt coins are treated as securities. The potential for ERC20 tokens to be classified as securities (under the aforementioned conditions) lies in their lack of uniqueness, making them fungible.

Leaving aside the discussion on fungibility versus non-fungibility for now, another significant factor hindering the growth of the blockchain market is the concept of a common enterprise within the Howey test. It examines whether the funds invested directly contribute to the development of something that can increase the value of the purchased object.

Object

Are they issued by a centralised entity?

Does entity spend funds on development that can add value?

Does the entity control future value?.

Is a change in value linked directly to issuers activities?

Is object sold to provide revenue for issuer?

Is it classed as a security?

Apple stock

yes

yes

yes

yes

yes

yes

Stamp

yes

no

no

no

yes

no

Gift cards

yes

no

yes

no

yes

no

Bitcoin

no

no

no

no

no

no

Ethereum

no

no

no

no

no

no

ERC20 tokens

yes

yes

no

no

yes

yes

Pokemon cards / Beanie babies etc

yes

no

no

no

yes

no

Fine art

yes

no

no

no

yes

no

NFTs (Blockchain based art/music etc’)

yes

no

no

no

yes

no

Cash (coins)

yes

no

no

no

no

no

Cash (notes)

yes

no

no

no

no

no

When examining the concept of common enterprise, there are two objects that are classified as securities: Apple stocks and ERC20 tokens. While Ethereum and Bitcoin are technologically similar to ERC20 tokens, they are not considered securities because they operate as decentralized ecosystems without ultimate control from any single party [H/R1]. Although they were initially centralized, they have evolved over time and are no longer under the jurisdiction of a single entity [H/R2].

The Hinman speech, along with the release of internal emails leading up to the speech, has created confusion in the blockchain space. The speech provided guidance on navigating the sector while avoiding excessive governance through decentralization [H/R2]. However, the emails suggest that Hinman went against the advice of various advisors before delivering his presentation. Additionally, the way in which tokens/coins are marketed plays a role in determining whether they are perceived as securities or not. The general idea is that if a token is sold with the expectation of profit, it is considered a security. Conversely, if a token is sold solely for its utility or use case, it is not classified as a security [6].

[6] Note the SEC may still contest it is a security, via civil suit, but the approach will be random and will not provide clarity to the market, at the same time they may provide a token the option for not registering with the SEC as a security as they’ve done so previously under a prior Exempt offering for a utility payment token.

Following the guidance provided by Hinman’s speech, many blockchain creators started developing their own ecosystems and blockchains before launching tokenization mechanisms. They aimed to encourage multiple mining operations and developers to contribute to the growth and ongoing strategy of the ecosystems, ensuring no single entity had complete control. By achieving sufficient decentralization, the concept of a common enterprise becomes irrelevant, making the Howey test inapplicable. However, it seems that certain regulators failed to recognize or ignored this approach.

Another point highlighted in Hinman’s speech was the way in which cryptocurrencies were sold and their potential classification as securities or investments [H/R3]. The industry interpreted this as a recommendation to offer tokens as tools to access live systems or networks without marketing them with promises of profit.

Considering the actions taken by security regulators against many blockchain operators, ERC20 tokens have been labeled as “securities” due to their fungible nature and issuance by a centralized entity. Furthermore, the fact that most ERC20 tokens are launched after the networks in which they operate are already live and accessible, serving as a revenue source rather than a development capital injection, is often overlooked [H/R4].

Given the current circumstances, I began exploring ways to combine the best aspects of both worlds and create a cryptocurrency that satisfies the Howey test while fitting into the category of objects not classified as securities due to rarity, uniqueness, and utility.

My goal was to create non-fungibility while maintaining functionality and utility—a fungible token that retains its value set by the market and utility while being distinguished by unique identifying elements embedded in its code. This is precisely what I have achieved with RiDT.

RiDT is an ERC20 token issuance mechanism that automatically incorporates a unique identifying code into each component. As a proof of concept, I have encoded a task within the 10 tokens I created. These tokens contain details for two wallets with  Bitcoin and Ethereum seeded within. The task is for crypto enthusiasts and developers to create a mechanism to decode and read the inscriptions, and reconstruct the  private keys before someone else does, generate a functioning read on the inscriptions across the multiple wallets (Inscription tokenID’s against the wallet address) on-chain or off-chain via listening functionality. This is intended to encourage developers to build new systems with inscription reading in mind and promote broader utilization of the token type, moving further away from being classified as securities. Each component of the tokens created using this technology is 100% unique, effectively making every individual part of each token a collectible in its own right. The specific inscriptions are determined by the coder or issuer of each newly minted token and this can be generated using generative AI to make it even more unique…

Some may argue that the ability to inscribe within ERC20 is not a new concept, citing ETHSCRIPTIONS as evidence. However, it’s important to note that this is not an individualistic approach where a message is placed in just one block. Instead, it is a method where every element is uniquely inscribed with its own one-of-a-kind identifier once launched. If someone wishes to create a token that combines the names of premier league footballers with a set of coins for collection, they can do so. The key element is that the ERC20 token will still maintain its utility within the ecosystem it is designed to function in. In other words, it can still be sent, bought, sold, and burned just like any other ERC20 token available today.

Currently, the inscriptions can only be viewed in the original wallet where they were created, as etherscan does not have the capability to read inscriptions once tokens are moved to a different wallet. It is essential to emphasize that this technology has not been developed as a way to circumvent global protocols that regulate blockchain/cryptocurrency. Instead, it is structured to potentially enable true digital representation of real-world assets on the blockchain. It can be utilized to provide proof of ownership for nearly anything, as long as unique assets can be adequately described, consider if you will T-Bills serials, or Kakubi certificates for EUA’s or similar.

Acts like a stamp

Acts like a gift card

Does not act like a stock or share

Acts like a collectible

Acts like Bitcoin and Ethereum

Acts like an NFT

Can be used as gas within its allocated network

Maintains a redeemable value for services within the network

No profits promised due to efforts of others

Individual and unique in all ways

Fungible and functional within allocated network

Blockchain based, uniquely identifiable components



When launching this, it is imperative that you do not paint it as any kind of investment [7]. Only to be used as a mechanism for accessing services at fixed value based on redeemable value of tokens.

[7] The classification of an object as a security or not is determined by the economic realities of the transaction, taking into account the specific facts and circumstances. If we were to label something as not a security solely because it is unique, fungible, or non-fungible, while ignoring statements related to wealth generation, it would negate the significance of the inscription aspect and revert back to the basic contract statements.

[H/R1]

Can a digital asset that was originally offered in a securities offering ever be later sold in a manner that does not constitute an offering of a security? In cases where the digital asset represents a set of rights that gives the holder a financial interest in an enterprise, the answer is likely ‘no.’. But what about cases where there is no longer any central enterprise being invested in or where the digital asset is sold only to be used to purchase a good or service available through the network on which it was created? I believe in these cases the answer is a qualified ‘yes’.

 U.S. Securities and Exchange Commission’s (SEC)  Director of Corporate Finance, William Hinman’s speech June 14, 2018.

[H/R2]

If the network on which the token or coin is to function is sufficiently decentralized… the assets may not represent an investment contract.

U.S. Securities and Exchange Commission’s (SEC)  Director of Corporate Finance, William Hinman’s speech June 14, 2018.

[H/R3]

Returning to the ICOs I am seeing, strictly speaking, the token – or coin or whatever the digital information packet is called – all by itself is not a security, just as the orange groves in Howey were not. Central to determining whether a security is being sold is how it is being sold and the reasonable expectations of purchasers. 

U.S. Securities and Exchange Commission’s (SEC)  Director of Corporate Finance, William Hinman’s speech June 14, 2018.

[H/R4]

I believe some industry participants are beginning to realize that, in some circumstances, it might be easier to start a blockchain-based enterprise in a more conventional way. In other words, conduct the initial funding through a registered or exempt equity or debt offering and, once the network is up and running, distribute or offer blockchain-based tokens or coins to participants who need the functionality the network and the digital assets offer. This allows the tokens or coins to be structured and offered in a way where it is evident that purchasers are not making an investment in the development of the enterprise.

U.S. Securities and Exchange Commission’s (SEC)  Director of Corporate Finance, William Hinman’s speech June 14, 2018.

Opportunity to Build Out and Recover BTC/ETH

Please refer to the following example: Example Link.

You can access the example below: Example Link. This platform allows you to query the blockchain and retrieve the stored information. The example contains the following:

  • Inscription
  • Link to a JPG file
  • Link to a JSON file

The inscription within the example consists of two wallets: one for ETH and one for BTC. The private keys associated with these wallets are encoded and encrypted.

This demonstration was a proof of concept in a previous version, available here: GitHub Repository Link.

Now, the challenge for aspiring developers or blockchain enthusiasts is to create a system that replicates the functionality of storing inscriptions in the blockchain in ERC20 tokens, giving them uniqueness (non-fungibility) alongside their fungibility… The system should also enable reading the stored data, either through function queries on the chain or by utilizing listening scripts that store the data in an oracle or a centralized table.

1) Ensure that you’ve been able to transfer the tokens of your compiled replication ERC20 token to fresh wallet(s), identify the token by it’s ID in a specific wallet (ID is its inscription). – query wallet to show token(s) in it, and query ID (inscriptions) for their wallet location.
2) Ensure that the function for this is accessible to the public for review (github) and use-access (online).
3) Document your process on Github and how it operates.
4) sign a message from the BTC wallet (recovered account with the private key) linking to your wallet (address).

When submitting the inscribed data, please include the following information:

  • ETH Wallet Address
  • BTC Wallet Address
  • Link to the GitHub repository containing the deployed and functional code, including .json, .php, .js, and .sol files
  • Link to a live version that displays the information.

Feel free to drop us a message here: Contact Form.

The first person to submit the completed tasks and prove their implementation of this concept in a functional manner against a token they’ve created, will be declared the winner. The ETH and BTC funds will be transferred to their respective wallets after D/D of their work. To prevent any unauthorized access, the funds will be moved to another wallet temporarily 27/6/23, serving as a demonstration of the total amount present in both wallets – determined when the private key is recovered.

 

Note: so as to avoid confusion, the expectation is that someone from the public is smart enough to take what’s been created here, and come up with a solution for tracking the Token_ID/Inscribe after a token moves wallet, we’ve provided the ground work, the person(s) that are able to achieve this, and recover the private keys from the inscribes on our example, will be awarded the funds in BTC, and ETH in the wallets associated to the reference Private Key(s).

The funds in those wallets have been moved to an adjacent wallet for manual distribution for fairness.

For instance, when extracting data from the blockchain, it is important to address any inaccuracies in the fetched results. This is where the incorporation of an off-chain listener becomes a tool, allowing the data to be stored in decentralized platforms like Oracles or IPFS, or even in a centralized database. This implementation leverages the non-fungible characteristics of tokens, which are intrinsic to their distinctive creation and inscription. Moreover, this approach enhances the utility potential of ERC20 tokens, expanding their applicability in a wide range of industrial and ecommerce solutions.

Only a single submission can claim the coveted rewards of Bitcoin and Ethereum, ensuring unparalleled success.

token.sol

“RiDT” (Research inscribable Data Technology) and it extends the functionality of the ERC20 token standard. It is designed to provide a token with unique characteristics and the ability to reference off-token centralized or decentralized data forms.

Let’s go through the functions of this contract:

  1. constructor(): This is the constructor function that initializes the contract. It sets the name and symbol of the token to “RiDT” and “RiDT” respectively. It also initializes the totalTokens variable to 10 and mints 10 tokens with 1 decimal place to the contract deployer. Additionally, it populates the tokens mapping with token information including inscriptions and URLs.

  2. getTokenInscription(uint256 tokenId) internal pure returns (string memory): This internal pure function takes a tokenId as input and returns the corresponding token inscription based on the token ID. The function uses a series of conditional statements to determine the inscription based on the value of the tokenId.

  3. getTokenURL1(uint256 tokenId) internal pure returns (string memory): This internal pure function takes a tokenId as input and returns the corresponding URL 1 of the token. Similar to getTokenInscription, it uses conditional statements to determine the URL based on the tokenId.

  4. getTokenURL2(uint256 tokenId) internal pure returns (string memory): This internal pure function takes a tokenId as input and returns the corresponding URL 2 of the token. It follows the same pattern as the previous two functions, using conditional statements to determine the URL based on the tokenId.

  5. getBalance() external view returns (uint256): This external view function returns the balance of the caller’s address, i.e., the number of RiDT tokens the caller holds.

  6. transferTokens(address recipient, uint256 amount) external: This external function allows the caller to transfer a specified amount of RiDT tokens to a recipient address. It checks if both the sender and recipient are not blacklisted before performing the transfer using the _transfer function inherited from the ERC20 contract.

  7. getInscription(uint256 tokenId) external view returns (string memory): This external view function takes a tokenId as input and returns the inscription associated with that token. It checks if the token exists in the tokens mapping before returning the inscription.

  8. getURL1(uint256 tokenId) external view returns (string memory): This external view function takes a tokenId as input and returns URL 1 associated with the token. It checks if the token exists in the tokens mapping before returning the URL.

  9. getURL2(uint256 tokenId) external view returns (string memory): This external view function takes a tokenId as input and returns URL 2 associated with the token. It checks if the token exists in the tokens mapping before returning the URL.

  10. getTokensInWallet(address wallet) external view returns (uint256[] memory, uint256[] memory): This external view function takes a wallet address as input and returns two arrays: tokenIds and tokenBalances. It iterates over all the tokens (from 1 to totalTokens) and checks the balance of each token in the wallet. If the balance is greater than zero, it adds the token ID and balance to the respective arrays. The function then resizes the arrays to remove any unused elements and returns the resized arrays.

The contract also includes a Token struct to store the inscription, URLs, and existence status of each token, and two mappings: tokens to map token IDs to their corresponding token information, and blacklist to keep track of blacklisted addresses.

Please note that the provided contract may have specific use cases and requirements that may not be fully explained here. It’s essential to review and understand the contract thoroughly before using it in a production environment.

				
					// SPDX-License-Identifier: MIT
// 2013-2023 Catena Capital - Research Labs Division
// RiDT [Research inscribable Data Technology]
// Created to provide an avenue to have a token (ERC20 compliant) that has 'unique characteristics', whilst also having the ability to reference off-token centralised or decentralised data forms.
// Enhanced ERC20 Token Generation Contract.
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract RiDT is ERC20 {
    struct Token {
        string inscription;
        string url;
        string url2;
        bool exists;
    }

    mapping(uint256 => Token) public tokens;
    mapping(address => bool) private blacklist;
    uint256 public totalTokens;

    constructor() ERC20("RiDT", "RiDT") {
        totalTokens = 10;
        uint256 decimalFactor = 10**decimals();

        for (uint256 i = 1; i <= totalTokens; i++) {
            string memory inscription = getTokenInscription(i);
            string memory url1 = getTokenURL1(i);
            string memory url2 = getTokenURL2(i);
            tokens[i] = Token(inscription, url1, url2, true);
            _mint(msg.sender, decimalFactor); // Mint 1 token with 1 decimal place
        }
    }

    function getTokenInscription(uint256 tokenId) internal pure returns (string memory) {
        if (tokenId == 1) {
            return "Inscription_1_Example_RiDT_Smart";
        } else if (tokenId == 2) {
            return "Inscription_2_Example_RiDT_Smart_";
        } else if (tokenId == 3) {
            return "Inscription_3_Example_RiDT_Smart_";
        } else if (tokenId == 4) {
            return "Inscription_4_Example_RiDT_Smart_";
        } else if (tokenId == 5) {
            return "Inscription_5_Example_RiDT_Smart_";
        } else if (tokenId == 6) {
            return "Inscription_6_Example_RiDT_Smart_";
        } else if (tokenId == 7) {
            return "Inscription_7_Example_RiDT_Smart_";
        } else if (tokenId == 8) {
            return "Inscription_8_Example_RiDT_Smart_";
        } else if (tokenId == 9) {
            return "Inscription_9_Example_RiDT_Smart_";
        } else if (tokenId == 10) {
            return "Inscription_10_Example_RiDT_Smart_";
        } else {
            revert("Invalid token ID");
        }
    }

    function getTokenURL1(uint256 tokenId) internal pure returns (string memory) {
        if (tokenId == 1) {
            return "https:/example.com1.png";
        } else if (tokenId == 2) {
            return "https:/example.com2.png";
        } else if (tokenId == 3) {
            return "https:/example.com3.png";
        } else if (tokenId == 4) {
            return "https:/example.com4.png";
        } else if (tokenId == 5) {
            return "https:/example.com5.png";
        } else if (tokenId == 6) {
            return "https:/example.com6.png";
        } else if (tokenId == 7) {
            return "https:/example.com7.png";
        } else if (tokenId == 8) {
            return "https:/example.com8.png";
        } else if (tokenId == 9) {
            return "https:/example.com9.png";
        } else if (tokenId == 10) {
            return "https:/example.com10.png";
        } else {
            revert("Invalid token ID");
        }
    }

    function getTokenURL2(uint256 tokenId) internal pure returns (string memory) {
        if (tokenId == 1) {
            return "https:/example.com/1.json";
        } else if (tokenId == 2) {
            return "https:/example.com/2.json";
        } else if (tokenId == 3) {
            return "https:/example.com/3.json";
        } else if (tokenId == 4) {
            return "https:/example.com/4.json";
        } else if (tokenId == 5) {
            return "https:/example.com/5.json";
        } else if (tokenId == 6) {
            return "https:/example.com/6.json";
        } else if (tokenId == 7) {
            return "https:/example.com/7.json";
        } else if (tokenId == 8) {
            return "https:/example.com/8.json";
        } else if (tokenId == 9) {
            return "https:/example.com/9.json";
        } else if (tokenId == 10) {
            return "https:/example.com/10.json";
        } else {
            revert("Invalid token ID");
        }
    }


    function getBalance() external view returns (uint256) {
        return balanceOf(msg.sender);
    }

    function transferTokens(address recipient, uint256 amount) external {
        require(!blacklist[msg.sender], "Sender is blacklisted");
        require(!blacklist[recipient], "Recipient is blacklisted");
        _transfer(msg.sender, recipient, amount);
    }

    function getInscription(uint256 tokenId) external view returns (string memory) {
        require(tokens[tokenId].exists, "Token does not exist");
        return tokens[tokenId].inscription;
    }

    function getURL1(uint256 tokenId) external view returns (string memory) {
        require(tokens[tokenId].exists, "Token does not exist");
        return tokens[tokenId].url;
    }

    function getURL2(uint256 tokenId) external view returns (string memory) {
        require(tokens[tokenId].exists, "Token does not exist");
        return tokens[tokenId].url2;
    }

function getTokensInWallet(address wallet) external view returns (uint256[] memory, uint256[] memory) {
    uint256[] memory tokenIds = new uint256[](balanceOf(wallet));
    uint256[] memory tokenBalances = new uint256[](balanceOf(wallet));
    uint256 tokenCount = 0;

    for (uint256 i = 1; i <= totalTokens; i++) {
        uint256 balance = balanceOf(wallet, i);
        if (balance > 0) {
            tokenIds[tokenCount] = i;
            tokenBalances[tokenCount] = balance;
            tokenCount++;
        }
    }

    // Resize the arrays to remove unused elements
    assembly {
        mstore(tokenIds, tokenCount)
        mstore(tokenBalances, tokenCount)
    }

    return (tokenIds, tokenBalances);
}
}
				
			

contractABI.json

ContractABI is a interface of ERC-20 token contract, which is a standard for fungible tokens on the Ethereum blockchain.

Let’s go through the different components of the code:

  1. Constructor: This is a special function executed only once during contract deployment. It initializes the contract when it is first created. In this case, the constructor doesn’t take any arguments (inputs) and is defined as nonpayable, meaning it cannot receive Ether (ETH) during its execution.

  2. Events: Events are used to emit information from a smart contract that can be captured and logged off-chain. This contract defines two events: Approval and Transfer. Both events contain indexed and non-indexed parameters (indexed: true/false). Events can be used to notify external applications about specific occurrences in the contract, such as when an approval or transfer of tokens takes place.

  3. Functions: The contract provides several functions to interact with the token:

    • approve: Allows the token owner to approve a specific address (spender) to spend a certain amount of tokens (amount) on their behalf.
    • decreaseAllowance: Decreases the allowance granted to a specific address (spender) to spend tokens by a specified amount (subtractedValue).
    • increaseAllowance: Increases the allowance granted to a specific address (spender) to spend tokens by a specified amount (addedValue).
    • transfer: Allows the token owner to send a certain amount of tokens (amount) to a specific address (recipient).
    • transferFrom: Allows a designated address (spender) to transfer tokens from another address (from) to a recipient address (to), provided that the spender has been approved to do so.
    • allowance: Retrieves the amount of tokens that a specific address (spender) is allowed to spend on behalf of another address (owner).
    • balanceOf: Retrieves the token balance of a given address (account).
    • getBalance: Retrieves the balance of the contract itself.
    • getInscription: Retrieves the inscription (a string) associated with a given token ID.
    • getTokenIdsInWallet: Retrieves an array of token IDs owned by a specific address (wallet).
    • getURL1: Retrieves the URL associated with a given token ID.
    • getURL2: Retrieves an alternative URL associated with a given token ID.
    • name: Retrieves the name of the token.
    • symbol: Retrieves the symbol (ticker) of the token.
    • totalSupply: Retrieves the total supply of tokens in existence.
    • totalTokens: Retrieves the total number of tokens that have been created.

The functions have different stateMutability modifiers, which specify whether they read data from the blockchain (view), modify the contract’s state without sending Ether (nonpayable), or modify the contract’s state while also accepting Ether (payable).

				
					[
	{
		"inputs": [],
		"stateMutability": "nonpayable",
		"type": "constructor"
	},
	{
		"anonymous": false,
		"inputs": [
			{
				"indexed": true,
				"internalType": "address",
				"name": "owner",
				"type": "address"
			},
			{
				"indexed": true,
				"internalType": "address",
				"name": "spender",
				"type": "address"
			},
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "value",
				"type": "uint256"
			}
		],
		"name": "Approval",
		"type": "event"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "spender",
				"type": "address"
			},
			{
				"internalType": "uint256",
				"name": "amount",
				"type": "uint256"
			}
		],
		"name": "approve",
		"outputs": [
			{
				"internalType": "bool",
				"name": "",
				"type": "bool"
			}
		],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "spender",
				"type": "address"
			},
			{
				"internalType": "uint256",
				"name": "subtractedValue",
				"type": "uint256"
			}
		],
		"name": "decreaseAllowance",
		"outputs": [
			{
				"internalType": "bool",
				"name": "",
				"type": "bool"
			}
		],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "spender",
				"type": "address"
			},
			{
				"internalType": "uint256",
				"name": "addedValue",
				"type": "uint256"
			}
		],
		"name": "increaseAllowance",
		"outputs": [
			{
				"internalType": "bool",
				"name": "",
				"type": "bool"
			}
		],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"anonymous": false,
		"inputs": [
			{
				"indexed": true,
				"internalType": "address",
				"name": "from",
				"type": "address"
			},
			{
				"indexed": true,
				"internalType": "address",
				"name": "to",
				"type": "address"
			},
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "tokenId",
				"type": "uint256"
			}
		],
		"name": "TokenTransfer",
		"type": "event"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "recipient",
				"type": "address"
			},
			{
				"internalType": "uint256",
				"name": "amount",
				"type": "uint256"
			}
		],
		"name": "transfer",
		"outputs": [
			{
				"internalType": "bool",
				"name": "",
				"type": "bool"
			}
		],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"anonymous": false,
		"inputs": [
			{
				"indexed": true,
				"internalType": "address",
				"name": "from",
				"type": "address"
			},
			{
				"indexed": true,
				"internalType": "address",
				"name": "to",
				"type": "address"
			},
			{
				"indexed": false,
				"internalType": "uint256",
				"name": "value",
				"type": "uint256"
			}
		],
		"name": "Transfer",
		"type": "event"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "from",
				"type": "address"
			},
			{
				"internalType": "address",
				"name": "to",
				"type": "address"
			},
			{
				"internalType": "uint256",
				"name": "amount",
				"type": "uint256"
			}
		],
		"name": "transferFrom",
		"outputs": [
			{
				"internalType": "bool",
				"name": "",
				"type": "bool"
			}
		],
		"stateMutability": "nonpayable",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "owner",
				"type": "address"
			},
			{
				"internalType": "address",
				"name": "spender",
				"type": "address"
			}
		],
		"name": "allowance",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "account",
				"type": "address"
			}
		],
		"name": "balanceOf",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "decimals",
		"outputs": [
			{
				"internalType": "uint8",
				"name": "",
				"type": "uint8"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "getBalance",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "uint256",
				"name": "tokenId",
				"type": "uint256"
			}
		],
		"name": "getInscription",
		"outputs": [
			{
				"internalType": "string",
				"name": "",
				"type": "string"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "address",
				"name": "wallet",
				"type": "address"
			}
		],
		"name": "getTokenIdsInWallet",
		"outputs": [
			{
				"internalType": "uint256[]",
				"name": "",
				"type": "uint256[]"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "uint256",
				"name": "tokenId",
				"type": "uint256"
			}
		],
		"name": "getURL1",
		"outputs": [
			{
				"internalType": "string",
				"name": "",
				"type": "string"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "uint256",
				"name": "tokenId",
				"type": "uint256"
			}
		],
		"name": "getURL2",
		"outputs": [
			{
				"internalType": "string",
				"name": "",
				"type": "string"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "name",
		"outputs": [
			{
				"internalType": "string",
				"name": "",
				"type": "string"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "symbol",
		"outputs": [
			{
				"internalType": "string",
				"name": "",
				"type": "string"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"name": "tokens",
		"outputs": [
			{
				"internalType": "string",
				"name": "inscription",
				"type": "string"
			},
			{
				"internalType": "string",
				"name": "url",
				"type": "string"
			},
			{
				"internalType": "string",
				"name": "url2",
				"type": "string"
			},
			{
				"internalType": "bool",
				"name": "exists",
				"type": "bool"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "totalSupply",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "totalTokens",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	}
]
				
			

tokenId_track.js

Listen for a specific event called “TokenTransfer” emitted by the blockchain and update an external MySQL database with the information from that event.

Here’s a breakdown of what the code does:

  1. It imports necessary dependencies such as the web3 library, the contract ABI (Application Binary Interface), the database configuration file, and the MySQL library.

  2. It initializes a web3 instance with the URL of the Goerli testnet provided by Infura. This allows the code to interact with the Ethereum blockchain.

  3. It creates a contract instance by providing the contract ABI and the contract address. The contract ABI is an interface that describes the functions and events of the contract.

  4. It connects to an external MySQL database using the provided database configuration (host, user, password, database, and port). Note that you would need to replace these values with your own database connection details.

  5. It sets up an event listener for the “TokenTransfer” event emitted by the contract. The .on('data', ...) function specifies the callback function to execute when a new event is received.

  6. The callback function extracts the relevant information from the event, including the from address, to address, and tokenId.

  7. The updateDatabase function is called to update the external MySQL database with the token transfer information. It constructs a query to update the database table with the received information.

  8. The executeQuery function executes the database query using the database connection and returns a promise that resolves with the query results.

  9. If the token transfer information is successfully updated in the database, a success message is logged. Otherwise, an error message is logged.

				
					const Web3 = require('web3');
const contractABI = require('contractABI.json');
const db_conf = require('db_conf.ini');
const mysql = require('mysql');

// Initialize web3 instance
const web3 = new Web3('https://goerli.infura.io/v3/####YourAPI###');

// Create contract instance
const contractAddress = '0xab8ae67a1143d21ec7aea4251062f9dfafe05240'; // Replace with your contract address
const contract = new web3.eth.Contract(contractABI, contractAddress);

// Connect to your external database (e.g., MongoDB, MySQL, etc.)
// Replace the following lines with your database connection code
const database = mysql.createConnection({
  host: db_host,
  user: db_user,
  password: db_pass,
  database: db_table,
  port: 3306,
});

database.connect(function(err) {
  if (err) throw err;
  console.log('Connected to the database');
});

// Event listener for TokenTransfer event
contract.events.TokenTransfer()
  .on('data', async function (event) {
    const { from, to, tokenId } = event.returnValues;

    // Update the external database with the token transfer information
    await updateDatabase(from, to, tokenId);
  })
  .on('error', console.error);

// Function to update the external database
async function updateDatabase(from, to, tokenId) {
  try {
    // Update the database with the token transfer information
    const query = `UPDATE tokenID_Track SET tokenId = ${tokenId} WHERE to = '${to}'`;
    await executeQuery(query);

    console.log('Token transfer updated in the external database:', from, '->', to, '(Token ID:', tokenId, ')');
  } catch (error) {
    console.error('Failed to update the external database:', error);
  }
}

// Function to execute the database query
function executeQuery(query) {
  return new Promise((resolve, reject) => {
    database.query(query, (error, results) => {
      if (error) {
        reject(error);
      } else {
        resolve(results);
      }
    });
  });
}
				
			

update_database.php

This is a PHP script that connects to a MySQL database, fetches token transfer data from a JavaScript listener, and updates the database with the received token transfer information.

Let’s break down the script:

  1. The ini_set('display_errors',1); line is used to enable the display of errors in case any occur during script execution.

  2. Database connection details are specified in variables: $dbHost, $dbName, $dbUser, and $dbPass.

  3. A try-catch block is used to establish a connection to the MySQL database using PDO (PHP Data Objects). The script attempts to connect to the database using the provided credentials and sets the error mode to throw exceptions if any errors occur during database operations.

  4. The fetchTokenTransfers() function is called to fetch the token transfer data from the JavaScript listener. This function should be replaced with your own logic for retrieving the token transfer data.

  5. A loop is used to iterate over each token transfer in the $tokenTransfers array. It assumes that each transfer is represented as an associative array with keys 'tokenId' and 'to', corresponding to the token ID and the recipient wallet address.

  6. Inside the loop, the script prepares a SQL statement to update the tokenID_Track table in the database. It binds the :tokenId and :walletAddress parameters to the corresponding values from the token transfer array and executes the statement using $stmt->execute().

  7. After updating the database with all the token transfers, the script closes the database connection by setting the $pdo object to null.

				
					<?php

ini_set('display_errors',1);

// Connect to the database
$dbHost = '####';
$dbName = 'tokenID_Track';
$dbUser = '####';
$dbPass = '####';

try {
    $pdo = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUser, $dbPass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("Database connection failed: " . $e->getMessage());
}

// Fetch token transfer data from the JavaScript listener (replace with your own logic)
$tokenTransfers = fetchTokenTransfers();

// Update the database with the token transfer information
foreach ($tokenTransfers as $transfer) {
    $tokenId = $transfer['tokenId'];
    $walletAddress = $transfer['to'];

    // Perform the necessary database update operations (replace with your own logic)
    // Update the relevant tables with the tokenId and walletAddress
    $stmt = $pdo->prepare("UPDATE `tokenID_Track` SET `tokenId` = :tokenId WHERE `to` = :walletAddress");
    $stmt->bindParam(':tokenId', $tokenId);
    $stmt->bindParam(':walletAddress', $walletAddress);
    $stmt->execute();
}

// Close the database connection
$pdo = null;
?>
				
			

web3_db_conn.php

This is a PHP script that connects to a MySQL database and retrieves wallet addresses and corresponding token IDs from the tokenID_Track table. It then displays the retrieved data in an HTML table.

  1. Database connection details such as the host, database name, username, and password are specified in variables: $host, $dbName, $username, and $password. Make sure to replace the placeholders with your actual database connection details.

  2. The script attempts to connect to the database using PDO (PHP Data Objects). It establishes a connection to the MySQL database using the provided credentials and sets the error mode to throw exceptions if any errors occur during database operations. If the connection is successful, it prints “Connected to the database” to indicate a successful connection.

  3. The script executes a SQL query using $pdo->query() to retrieve distinct wallet addresses (to) and token IDs (tokenId) from the tokenID_Track table. The query selects all distinct rows from the table.

  4. If the query returns any rows (i.e., the result set has a row count greater than zero), the script displays the retrieved data in an HTML table. It first prints a heading “Wallet Addresses and TokenIDs” and then starts building the table structure using HTML tags (<table>, <tr>, <th>, <td>, etc.).

  5. Inside the loop, the script fetches each row from the result set using $statement->fetch(PDO::FETCH_ASSOC). It assigns the values of the 'to' and 'tokenId' columns from the fetched row to the variables $walletAddress and $tokenId, respectively.

  6. The script then echoes the HTML table row (<tr>) with the wallet address and token ID values inside the table data cells (<td>).

  7. After looping through all the rows and displaying the data in the HTML table, the script closes the table structure using the appropriate HTML tags.

  8. If the query doesn’t return any rows, the script simply displays the message “No wallet addresses with tokenIds found in the database.”

  9. If an exception occurs during the database connection or query execution, the script catches the PDOException and displays an error message indicating the failure to connect to the database.

				
					<?php
// Replace with your database connection details
$host = '####';
$dbName = 'tokenID_Track';
$username = '####';
$password = '####';

try {
    // Connect to the database
    $pdo = new PDO("mysql:host=$host;dbname=$dbName;charset=utf8mb4", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo 'Connected to the database<br>';

    // Retrieve all wallet addresses and tokenIds
    $statement = $pdo->query('SELECT DISTINCT `to`, `tokenId` FROM tokenID_Track');

    if ($statement->rowCount() > 0) {
        echo '<h2>Wallet Addresses and TokenIDs:</h2>';

        echo '<table>';
        echo '<tr><th>Wallet Address</th><th>Token ID</th></tr>';

        // Loop through the results and display them in a table
        while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
            $walletAddress = $row['to'];
            $tokenId = $row['tokenId'];

            echo '<tr>';
            echo '<td>' . $walletAddress . '</td>';
            echo '<td>' . $tokenId . '</td>';
            echo '</tr>';
        }

        echo '</table>';
    } else {
        echo 'No wallet addresses with tokenIds found in the database.';
    }
} catch (PDOException $e) {
    echo 'Failed to connect to the database: ' . $e->getMessage();
}
?>
				
			

We appreciate your feedback and the extension of the idea. It’s indeed fascinating to explore the concept of extending ERC20 tokens from their traditional fungible nature to incorporate non-fungible characteristics. By doing so, we can enhance various areas of commerce on the blockchain.

For example, asset-backed tokens, such as those backed by real-world assets (RWA), can have their certificates and titles inscribed directly onto the blockchain. Consider tokens like “Kakubi,” which are backed by EUA (emission units) or “Tether,” which is backed by T-Bills. Inscribing the relevant information onto the blockchain provides transparent and immutable proof of ownership and facilitates efficient transfer of these assets.

Additionally, tokens that are considered securities (ERC20) can benefit from incorporating elements of non-fungibility. This further strengthens the notion that these tokens can be treated as commodities or collectibles while still retaining their fungible characteristics. It opens up possibilities for inscribing utility or service offerings within the tokens themselves. For instance, a token could represent a payment voucher or credit, entitling the holder to specific services or benefits.

Furthermore, projects can leverage the non-fungible aspects of tokens to incorporate specific functionalities within the token. For example, an individual token might represent the ability to utilize a certain amount of data on an oracle or a similar service. This allows for more intricate and nuanced interactions between token holders and various services or platforms.

By expanding the capabilities of ERC20 tokens to include non-fungibility, we can unlock a wide range of possibilities for tokenizing assets, enhancing security, and enabling new forms of value exchange and utility within the blockchain ecosystem.