Chapter 2. Token Fundamentals

In this chapter we’re going to take a deep dive and explore what tokens are, what its history is in the blockchain world and build the conceptual framework around what tokens can offer us. We’ll evaluate some of the token strategies that can be employed, like asset tokenization and stablecoins. We’ll also look at enterprise tokens, tokens that are used between enterprises or in a business-to-business fashion, how these tokens are just a way for cryptocurrencies and blockchain technology come back full circle in the permissioned world. This chapter covers the core and critical concepts we need to think about it and have under our belts before jumping into development of a token application. Make no mistakes, building large-scale enterprise token systems is not a trivial task, because it is intertwined with many other disciplines like economics, game theory, user behavior, token redemption, potential KYC/AML requirements and more.

Just to whet (temper?) your appetite, in the chapter after this we’ll take the concepts covered in this chapter and use them to build a token application by creating our own framework as well as building a token application using Corda’s token SDK, an open source Kotlin library created by Roger Willis of R3. For our application in the next chapter, we’ll build an arbitrary settlement token that can be used by any number of parties to net out trades of any goods. If you’re already grounded in the fundamentals of token you may wish to jump to the next chapter, although I highly recommend you peruse this chapter first. If you are new to tokens or only have dabbled with it, whether via some readings, engaging in an initial coin offering (ICO or STO) or attending talks here and there then this chapter is a must read.

What are tokens?

Crudely and broadly defined, a token is a thing that represents another thing. In its most fundamental and literal sense, a token is information that is used to represent some other set of information, if we are to regard any object or activity as just information, like location, time, action, value, size, color, type, etc. More practically speaking, a digital token represents one or more things or objects. The represented object can be anything, either virtual, abstract, tangible or intangible. A token can represent a physical asset, human behavior, a financial obligation, publicly exchangeable value (i.e. currency), prepaid gift card, airspace above a building, hydrogen molecules or anything else our hearts desire.

The reason I like to define tokens this broadly is to enable you to think about all the different use cases and applications tokens may have and not be pigeon-holed into preconceived ideas around what tokens are how they are used.

All of use tokens everyday, often not realizing it or not thinking about it. We can think of currency, whether fiat or digital, as a type of token. A fiat currency note, such as a $100 US dollar note, is a token that represents financial value. At one point the dollar note represented some amount of gold which represented financial value based on the supply and demand of metal and belief around the value of that metal. Today, a US dollar note simply represents a belief system around the value of the note itself. The note, a piece of paper or a token with physicality, is used to store information, including the value it represents, a unique serial number and counterfeit protection mechanisms. It also carries an implicit contract regarding its ownership, a contract that states the entity that has physical possession of the note is, with some exceptions, the owner of that note.

Why do we use tokens?

Typically, a token has capabilities and properties that the object it represents does not. Value, for example, requires a form of representation. If we think of value as continuous and nebulous (i.e imagine thinking about $100 million dollars of value without the dollar units), we use tokens to allow us to decompose, make transferable and assign ownership to this value. Fiat currency is created with this purpose, to provide to value properties that value itself cannot provide, namely transferability, identification of who the owner is, allowing for a unit of account, medium of exchange and more.

When thinking of tokens and what use cases can benefit from tokens, and in the context of a token system we may build on blockchain, we can think of tokens as an arbitrary label for arbitrary value, where that value can potentially and intentionally be zero, potentially just a marker in its most simplest form. What it can be above and beyond this base definition is really up to you, the token designer and (possibly your attorneys, regulatory bodies and more), depending on what the purpose and use of the token is. The reason I push this definition is that it allows people to think more freely about how tokens can be applied in current or new use cases without being bound to existing business interpretations of what a token should be.

However, from a business point of view, a token typically implies some type of obligation between the issuer of the token and its current holder, potentially providing the holder certain rights against the issuer. The token also can potentially provide transparency and visibility to the issuer about the holder and their behavior and usage patterns of the issued tokens. The insights that can be derived from the movement of tokens between parties across time can be in itself be interesting and critical to businesses that are looking to capture new or optimize existing revenue.

Because tokens are digital, what a token truly is and what it represents can become a deep philosophical discussion or debate, which we in general will avoid in this book . Also,. A token is a superset of that feature set, although there is clearly overlap and potentially gray area between the definition of the two. I think of tokens as a base class and a coin as a subclass, extending a token with specific purchasing powers.

[Sidebar: In this book, we differentiate a token and a coin (or cryptocurrency). I hold that a coin is just a token that has the additional feature of having purchasing power, power that can be used in a retail market to trade for real world goods or services. It may not be the best definition, and that’s because the labels we have traditionally used, like currency and money, no longer suffice as innovation is blurring the lines between what we thought were discrete, clean definitions.]

The era of tokens is upon us

Tokens are a significant, if not potentially dominant, application and use case for blockchain and distributed ledger technologies. Tokens are just as applicable to gaming apps as they are to the central bank of a country that may be exploring netting foreign currency transfer and exchanges between other central banks. Tokens will be to movement of value what TCP/IP is to movement of information and blockchain technology, with its ability to maintain immutable records and prevent double spending will enable this capability. Corda is uniquely positioned to be the foundational technology to support this shift up the value stack.

Before we delve into tokens, it’s a good idea to look at how we’ve evolved to this place in history where tokens are an important topic.

A brief history of tokens on blockchain

We’ll start the history of tokens at the time Bitcoin is launched in 2009. We’ll see how Bitcoin, a token representing financial value, relied on a rigid data structure. The next major evolution of the blockchain, Ethereum, expanded how tokens could be created and designed, providing more flexibility than the rigid data structures while maintaining some of the rigid structured transactions for its native cryptocurrency called ether. Finally, blockchains like Corda come back full circle by giving developers a completely blank slate to design tokens.

Bitcoin as a rigidly defined token

We can regard Bitcoin as a token with purchasing power and loosely define a cryptocurrency as a token that is expected to have some of the features we expect money, such as purchasing power. Not all tokens are cryptocurrencies but all cryptocurrencies are tokens. The Bitcoin blockchain defines and uses a set of data structures, like inputs, outputs, transaction and amount, for the exchange of a token, commonly known as Bitcoins, between two parties.

These data structures are rigid and well-defined and cannot be modified because they serve a singular purpose of specifically capturing the transaction of Bitcoins. If you look at the Bitcoin source code (https://github.com/bitcoin/bitcoin) , you’ll see that a transaction class is rigidly defined for the specific purpose of capturing the movement of Bitcoins from one user to another. A user of the Bitcoin blockchain is not free to modify this rigid data structure.

Below is the actual C++ code for a transaction class in Bitcoin. You don’t need to really know C++ to see that there is a vector of inputs and outputs (vin and vout, respectively), similar to how Corda transactions are structured. The difference is the transaction input class CTxIn and output class CTxout are predefined and cannot be modified. Effectively, its not possible to create a smart contract on the Bitcoin blockchain.

class CTransaction

{

public:

static const int32_t CURRENT_VERSION=2;

static const int32_t MAX_STANDARD_VERSION=2;

const std:: vector< CTxIn > vin;

const std:: vector< CTxOut > vout ;

const int32_t nVersion;

const uint32_t nLockTime;

.

.

}

A CTxIn refers to the outputs, or outpoints represented by COutPoint, of a previous transaction, and we can traverse back in time jumping from one UT eventually arriving at the coinbase transaction, the first transaction in a block, where a miner is awarded Bitcoins and Bitcoins are minted. This is why Satoshi Nakomoto defines in the Bitcoin white paper that a Bitcoin is a chain of digital signatures.

class CTxIn

{

public:

COutPoint prevout;

.

.

}

class CTxOut

{

public:

CAmount nValue;

CScript scriptPubKey;

..

}

class COutPoint

{

public:

uint256 hash;

uint32_t n;

..

}

Source: https://github.com/bitcoin/bitcoin/blob/master/src/primitives/transaction.h

https://github.com/bitcoin/bitcoin/blob/master/src/primitives/transaction.cpp

Above transactions, blocks are used to aggregate and bucket transactions. Because of deliberately slow consensus mechanisms like public proof of work, transactions need to be processed in batches as consensus is established. The batches are stored in blocks with each block containing meta data in the block header.

When peeking inside any block of the Bitcoin chain we can conceptually see that transactions are stored using these data structures.

Figure 2-1. In the block above, let’s block ID #17, we have the block header metadata and transaction data areas of a representative Bitcoin block. This is largely the architecture of all Bitcoin blocks with minor exceptions to the genesis block. We can conceptually view the transaction data, or red area, as rows of transaction data containing inputs and outputs, almost like a table containing rows of data, with one transaction per row. The data structure is fixed and it’s not possible to store any other type of data in the transaction data section of a block.

Ethereum: Programmable tokens with rigid transactions

In 2015, Ethereum was released and it decided to add flexibility into these data structures, allowing developers to not only store code and arbitrary logic into Ethereum blocks but also custom data. Much like the Bitcoin blocks, an Ethereum block had similar block header meta data and a list of Eth transaction but also sections of the blocks held smart contract code, in blue in XXX, and custom data models.

Figure 2-2. The ability to store arbitrary logic and custom data on a blockchain, known as smart contracts, ushered in a new era of decentralized applications, where the code and user defined data structures were stored on the blockchain (inside of blocks) and were available, invocable and accessible to the general public.

One of the first and most prominent use cases of Ethereum smart contracts was the creation of tokens and the sale of these tokens to the public, known as initial coin offerings or ICOs, as a means of raising capital or crowdfunding. The ability to issue tokens and maintain a registry of the parties that purchased the tokens became the backbone for the ICO boom from roughly the years 2016 through 2018.

On the Ethereum chain, every account address is effectively a public key (technically, it is a twice hashed, base 58 rendition of a public key). These addresses were used to construct allocation tables (think of Kotlin/Java hash maps, Python dictionary or Excel lookup tables) to associate an Ethereum address with some number. The number represented the quantity of tokens held by the address and were stored in the data portion of a smart contract. An example of such an allocation table is depicted below, with abbreviated hash addresses. In the table below, the Ethereum address 09AF3… held 5 tokens. Five was just a number

Token Allocation Table
Address Hash Token Quantity
09AF3... 100
7EF2D...

If you were to purchase 100 tokens for some amount of ether, your Ethereum address would get added to this allocation table and the number 100 would be associated to your address. To purchase the token, you would invoke the smart contract and pass with the invocation the required number of ether. This was all it took to sell tokens on the Ethereum chain. A smart contract would conceptually look partially like this

class Crowdsale (var tokenSupply: Int) {

val balances: HashMap<String,Int> = hashMapOf()

fun buyTokens(buyer: String, amount: Int) {

if (amount < tokenSupply) {

balances[buyer] = amount

tokenSupply =- amount

}

}

.

.

.

.

}

A user can invoke the buyTokens function of the smart contract passing in Ether (or Wei) and be allocated tokens. The balances hash map represents a custom data structure that functions as a registry and allocation table for our buyers. A Solidity version of this code, based on the Open Zeppelin Crowdsale smart contract

function buyTokens(address beneficiary) public nonReentrant payable {

uint256 weiAmount = msg.value;

_preValidatePurchase(beneficiary, weiAmount);

// calculate token amount to be created

uint256 tokens = _getTokenAmount(weiAmount);

// update state

_weiRaised = _weiRaised.add(weiAmount);

_processPurchase(beneficiary, tokens);

emit TokensPurchased(msg.sender, beneficiary, weiAmount, tokens);

_updatePurchasingState(beneficiary, weiAmount);

_forwardFunds();

_postValidatePurchase(beneficiary, weiAmount);

}

Corda: Coming full circle

When it came to rich data models, enterprise blockchains go a step further and allow for all of the data stored in a blockchain to be custom and user defined, entirely eliminating any native data structures related to currencies. Corda takes exactly this approach and we’ve been designing these custom data types as states since Chapter 2. In fact, because consensus could occur instantaneously once a transaction is fully signed, the need for blocks that bucket, batch and aggregate transactions disappear.

Figure 2-3. By default, Corda gives us a completely blank slate to design custom data types on the ledger. There are no pre-defined data structures like there on the Bitcoin and Ethereum blockchains.

Because we can define data types as we wish in an enterprise blockchain, it should come as no surprise that we come full circle by allowing the notion of tokens to exist as a custom data type. From Corda’s perspective, a token is just a custom data structure with arbitrary logic associated with it to encapsulate its behavior. There is one big difference however. Tokens created on a ledger like Corda (or HyperLedger, etc.) do not have public market valuation and maintain a value only as long as the private parties that agree to exchange them agree to the value.

Figure 2-4. Tokens are just a custom data structure in an enterprise DLT.

Corda empowers us to create our own tokens with features and aspects we wish to include, as well as giving those tokens the type of behaviors we wish the tokens to have. Token designers can focus on what tokens look like and do with as much creativity as they wish. Let’s now look at how we can start coding some basic tokens, starting off with a very basic self-referencing token and incrementally adding complexity to it.

Illustrating token fundamentals with code

At the simplest level, a token can be an empty class. By creating tokens as just an empty class, we have a baseline to understand it and then start to intuitively piece together and incrementally weave in more complex ideas into the token. A bare minimum token class would like so.

class Token()

Note that in Kotlin a class can be defined without the open and close brackets.

Creating a single token instance would look like this:

val token = Token()

What does this token do? What does it represent? At this point, the token represents nothing and can potentially represent anything, but at minimum represents itself if doesn’t represent anything else. It is a very generic token representing some arbitrary value or something. As simple as this concept seems, it is quite profound because we are now digitizing representation, the token being a digital representation of something without having to digitize that thing. For example, this token, with some tweaks, can potentially represent a credit default swap or some financial instrument without us having to take the difficult and error-prone steps of digitizing the physical contract into a PDF and making the PDF tradeable or transferable.

Our trivial Token class, although simple and minimal, does have some important characteristics we can infer and need to bring to your attention. Some of these may seem obvious, philosophical and basic but these characteristics play an important role when we start to design more advanced tokens and token behavior.

First the unit of value token represents is one, just by the nature of the fact that it exists. It contains no information about any other units or value except that it is present and that it is a single unit of value. What that value means to us, the user, society, some CorDapp or the real world, is at this point arbitrary and irrelevant, but will have some basis in the ecosystem the token plays in and the token’s life cycle, as we’ll see shortly. As currently designed, all we need to know is that it represents some value. A single token is intrinsically a single unit of itself. The unit, and therefore any potential value it may represent, is not divisible and the number of units it represents, in this case just one, is constant.

We get all of this from a single Token class.

If we wanted to create a bunch of these tokens we can do so using some type of data structure like an Array. In the below line of code, we create 50 tokens and store it in the variable tokens. The Array data structure takes a second parameter which is a lambda function allowing you to initialize each element of the array. Kotlin allows the lambda function to sit outside the instantiation call inside the squiggly brackets. In this case, we initialize each element to a single instance of Token

val tokens = Array(50) { i -> Token() }

A pool of these tokens, like contained in the variable tokens, can be divided or merged and tokens can be taken out of or inserted into the pool. But each specific token itself is not divisible and cannot be merged with other tokens to create a larger token. As we’ll see shortly, the concept of pools of tokens and a token pool blur if a single token can be combined or divided. Our current Token class’s inability to merge, known as fungibility, can create some issues as we’ll see in the coming sections.

Token ownership

Let’s start to add some basic features to our Token class. The most fundamental behavior a token can have is that it is transferable to someone else. Transferability implies ownership, that a token has a current owner of it. Tokens are typically associated with an owner and are usually, but not necessarily, first owned by an issuer or creator of that token. In our Token class, there is no information regarding an owner and we’ll want to include that. Without ownership information, a token is not tradeable and relegated to being merely a stationary counter. If we want our token to have the ability to be traded, redeemed or exchanged then it requires an owner.

We can easily embed ownership information into the class but it is worth to note that there are two broad approaches for us to track owners of tokens.

The first approach is to embed a property into the Token class to reflect the current owner and the second approach is to have an Account class that tracks balances of tokens. Bitcoin uses the former, where a satoshi, the smallest unit, and 1 / 100,000,000 of, a Bitcoin can be divided into, is associated with an owner as opposed to sitting in an owner’s account and Ethereum uses the latter where tokens are held in accounts identified by the Ethereum address. Corda lets you decide either approach, leaving it to you to fit your approach into your use cases in a manner you feel is best.

In the first approach, our token class has an owner property and change of ownership looks like this

Figure 2-5. If there are 5 or 50,000 tokens that need to be transferred from John to Linda, there will be many instances of each token. Every token’s owner property needs to be modified simultaneously in a single transaction to reflect the new owner.
Figure 2-6. The fact that each token needs to be modified independently can be an issue. Why? A very large amounts of tokens changing hands can lead to a load on the underlying ledger database where thousands of rows are locked for update. For very active token applications with a high volume of token turnover and flipping, this can inhibit scalability.

The second approach of tracking tokens is to use an account model that tracks just the token balances, similar to what we saw in the Ethereum allocation tables. In the below depiction, we can see that John transfer 5 tokens to Linda. Only account balances are debited and credited and tokens are just line items in an account.

Figure 2-7. It is entirely possible to take the first approach and reconstruct a view that looks like the second approach. Its what crypto wallets do, after all. However, on the ledger both approaches are distinct and different data models.

Token with owner

Let’s continue with our basic token example by now adding in ownership semantics. To do so, we can simply add an owner: String property to our Token class. The property will specify the string name of the current owner of the token. Transfers of ownerships would simply require the owner property to change. A transaction would then encompass the state change of a token’s ownership. Let’s modify our Token class a bit to incorporate this:

data class Token (var owner:String)

TODO: decide on whether to use property or attribute

Our new token class now has an owner property. We also converted it to a data class for the convenience methods we get for free provided to us by Kotlin (more on convenience methods and their Java equivalents in the Kotlin crash course at the end of this book). We can issue a token and have it assigned to John

val token = Token(“John”)

Types of tokens

Also missing from our trivial token example is the ability to create different types of tokens, classifications, pools or tranches of tokens we may wish to have. Unless you plan on creating a single general purpose token that is used for everything in the universe (not advised), you will find use cases where you need to create named pools of tokens, each pool of tokens used for a specific purpose and that purpose only. With our basic Token class there is no information in the token to differentiate one category of token from another. Sometimes this is a desired outcome, other times it is not TODO. For example, we can easily create several tranches, classification or pools of tokens using Arrays like so:

val loyaltyTokens = Array(30) { i -> Token(“John”) }

val settlementTokens = Array(30) { i -> Token(“Tina”) }

val videoGameTokens = Array(30) { i -> Token(“Lara”) }

We’ve created three categories of tokens: loyalty, settlement and video game tokens that happen to be owned by three different individuals and each pool contains exactly 30 tokens. Ideally, each token should be used independently of others in their own respective economic ecosystem with no commingling. We can demonstrate how easy it is to commingle the three types of tokens with one line of code:

loyaltyTokens.set ( 0,settlementTokens.get (0))

println(loyaltyTokens.get(0))

println(settlementTokens.get(0))

Output:

Token(owner=Tina)

Token(owner=Tina)

In the above code, a token from the settlementTokens pool all owned by Tina is inserted into the loyaltyTokens pool which is all owned by John. Aside from the loss of a loyalty token overwritten by the set() method and a potential double spend situation of two copies of the same settlement token existing, the token types are conflated, mixed up and, worst, indistinguishable. Unless we know in advance, we have no way of differentiating the settlement token from the loyalty token. All 30 of the loyaltyTokens look identical to each other despite the fact that we know the first token in that array is really a settlement token.

Clearly, this is not something we want, we really don’t want a token of particular type to be mixed up with tokens of another type. We can resolve this by shifting the knowledge about the token type and embedding an identifier into the Token class. We can call this identifier tokenIdentifier and let it help us clearly classify token types.

data class Token (var owner:String, val tokenIdentifier: String)

We can now recreate our tokens, but this time assign each type of token an arbitrary string identifier. In our case, we’ll use a 3 character identifier, similar to a stock ticker symbol. LYL tokens are loyalty tokens, STL are settlement tokens and VIDs are video game tokens.

val loyaltyTokens = Array(5) { i -> Token(“John”, “LYL”) }

val settlementTokens = Array(5) { i -> Token(“Rick”,"STL”) }

val videoGameTokens = Array(5) { i -> Token(“Sam”, “VID”) }

Borders between token types should not be porous, meaning that a token of one type or classification should not appear in a pool of another tokens. In our current design, the border between token pools is still porous, and we’ll address this with generics in the next section, but a token that has crossed borders from one Array into another Array, or from one token pool to another pool is now identifiable. We can redo our example and see that a settlement token appears in a pool of loyalty tokens. TODO

loyaltyTokens.set(0,settlementTokens.get(0))

println(Arrays.toString(loyaltyTokens))

println(Arrays.toString(settlementTokens))

Output:

[Token(owner=Rick, tokenIdentifier=STL), Token(owner=John, tokenIdentifier=LYL), Token(owner=John, tokenIdentifier=LYL), Token(owner=John, tokenIdentifier=LYL), Token(owner=John, tokenIdentifier=LYL)]

[Token(owner=Rick, tokenIdentifier=STL), Token(owner=Rick, tokenIdentifier=STL), Token(owner=Rick, tokenIdentifier=STL), Token(owner=Rick, tokenIdentifier=STL), Token(owner=Rick, tokenIdentifier=STL)]

In the above output, even though we are still getting away with moving an STL token into the LYL pool, we can readily identify the anomalous STL token in the LYL array.

Controlling the volume

In our latest incarnation of the Token class, the number of tokens we instantiate per token type is controlled externally by sizing an Array and setting the number of elements (i.e. val loyaltyTokens = Array(5)). We would preferably want the token pools to maintain and manage its own size. By doing this, we can strengthen the borders around token pools and programmatically disallow movement of a token from one pool into another pool. To shift the knowledge of the number of tokens issued from outside token to into the class we can add an amount field:

data class Token (var owner:String, var amount: Int, val tokenIdentifier: String)

Now we can issue a pool of a token of a stated quantity and identifier. Here, we’ll create another 100 loyalty LYL tokens, and assign ownership to the issuer. The quantity in the pool is stored internally in Token.

val loyaltyTokens = Token(“Issuer”,100,"LYL”)

println(loyaltyTokens)

Output:

Token(owner=Issuer, amount=100, tokenIdentifier=LYL)

Now our Token class can control the number of tokens it represents. Does this mean Token should be called TokenPool? After all, in the case of the loyaltyTokens, aren’t there actually 100 tokens in the pool instead of single token? Yes and no. As mentioned before, the granularity of a token cause it to blur with the notion of a token pool. For now, we’ll use it interchangeably. A dollar is ultimately a pool of pennies and $100 dollar bill a pool of $1 bills, but none of these are considered currency pools. The fact of the matter is, a token and a pool of tokens are fungible, indifferent representations of each other, both ultimately represent the quantity of tokens and the divisibility of a token. The difference is where that information is stored, whether it is external to the token or internal state information. By keeping the information internal to the Token class, how divisible a token can be controlled, whereas if it that information is held outside the Token, in an array of tokens, for example, then divisibility is subject to the programming language used to describe that array.

Transferring tokens out

By adding ownership and amount information to the token, we have now made the tokens tradeable. When we wish to transfer a token to another owner, how do we establish their ownership if our Token class can hold only one owner? If all 100 of our loyaltyTokens are currently owned by Issuer and we wish to transfer only a portion of it, we can do so be giving the recipient of the transfer their own Token instance containing the amount of tokens we wish to send them and then deducting from the number of LYL tokens held by the issuer.

To do this, we’ll create a transferTo method whose responsibility is to receive the name of a new owner and the quantity of tokens they will receive, deduct the outbound amount and return a new Token instance containing quantity of tokens for the recipient.

fun transferTo(newOwner:String, transferAmount: Int) : Token {

if(this.amount > transferAmount) {

this.amount -= transferAmount

return Token(owner = newOwner, amount = transferAmount, tokenIdentifier = tokenIdentifier)

} else

return Token(owner = newOwner, amount = 0, tokenIdentifier = tokenIdentifier)

}

The transferTo method accepts two arguments, a string for the new owner and a transfer amount which represents the number of tokens to be sent to the new owner. Before performing the transfer, we need to make sure there are a sufficient number of tokens to fulfill the transfer request. If there are, the requested amount is deducted from the Issuer and a new Token instance is created. The new Token instance contains the new owner’s information, the transfer amount and the same token identifier.

fun main() {

val stableCoins = Token(“Issuer”, 10, “STBL”)

println(stableCoins)

val bob = stableCoins.transferTo(“Bob”,3)

println(bob)

println(stableCoins)

}

Token(owner=Issuer, amount=10, tokenIdentifier=STBL)

Token(owner=Bob, amount=3, tokenIdentifier=STBL)

Token(owner=Issuer, amount=7, tokenIdentifier=STBL)

We can test how this works by creating a pool of 10 tokens called stableCoins with the identifier of STBL. The first line of the output shows that it is created successfully. We then call the transferTo function to transfer 3 of the 10 tokens to Bob. The transferTo function returns a new Token instance that is then associated to the variable bob. The second line of the output shows that a Token instance does in fact belong to Bob and contain the 3 tokens that were transferred out. The last line of the output shows that the original stableCoins Token instance’s balance is now expectedly reduced by 3 tokens with a net balance of 7 tokens. Conceptually speaking, what we’ve done is now made a token divisible. We can take a token and split it into two halves if we desired.

Transferring tokens in

Just as I can take a Token class and transfer amounts out of it, resulting in a new Token instance with the new owner associated to it, I should be able to transfer tokens into an existing Token instance. Transferring tokens of the same type (same tokenIdentifier) would effectively be a merge, where the tokens sent would be entirely absorbed by the recipient. To accomplish this, we’ll create a combineWith method in the Token class. It’s job is to first make sure the tokens sent to it are of the same token type and then update the amount adding in the newly received tokens to its internal balance.

fun combineWith (tokens:Token) {

if(tokens.tokenIdentifier==tokenIdentifier) {

amount += tokens.amount

tokens.amount = 0

} else

throw Exception(“Mismatched token”)

}

The co

In the combineWith method above, a Token instance is passed in as an argument. The first order of business is to make sure that tokenIdentifiers match. If they don’t match then we need to reject the attempt to combine. This condition logic provides us with the border and safeguards we need to prevent commingling of token types. Recall that, earlier commingling was possible when we tracked tokens using Arrays. Later in this chapter, we’ll further improve our commingling defenses using generics. If the token identifiers match then we are combining tokens of the same type and the next two lines take care of some accounting work, namely adding the new tokens to the current balance and then updating the inbound Token’s amount to zero.

Using the Kotlin infix operator

To make our combineWith method a bit more readable, we’ll modify it and append the infix keyword to the front of the method declaration. This makes the code more readable and we’ll see the Corda SDK use this approach.

infix fun combineWith (tokens:Token) : Token {....

The infix operator allows us to use the method name as an operator. Let’s now use the combineWith method and see it in action.

val ts = Token(“Issuer”,100,"ABC”)

println(ts)

val bob = ts.transferTo(“Bob”,20)

println(ts)

println(bob)

ts combineWith bob // Same as ts.combineWith (bob)

println (ts)

println (bob)

Output:

Token(owner=Issuer, amount=100, tokenIdentifier=ABC)

Token(owner=Issuer, amount=80, tokenIdentifier=ABC)

Token(owner=Bob, amount=20, tokenIdentifier=ABC)

Token(owner=Issuer, amount=100, tokenIdentifier=ABC)

Token(owner=Bob, amount=0, tokenIdentifier=ABC)

This ability to pull out a token using the transferTo method and fungibly combine token amounts into a single token instance with the combineWith method. Our Token class is effectively a fungible token because its semantics and behavior allows for the splitting and combining of tokens of the same type.

Non-fungible tokens

Our token example thus far has been fungible, a token that can be split and combined with other tokens like it. However, there are times we may need tokens that are not fungible. Instead we’ll want a token that represents a very specific thing or asset. Non-fungible tokens, or NFTs for short, are tokens that reference a specific thing and that thing only. A good example is a token that represents a specific house. A non-fungible token has no need for an amount property, and much like our first primitive iteration of the Token class in XXX, is a single non-divisible and non-combinable unit.

How do you know if you need a fungible or non-fungible token for your use case? Here is a simple heuristic I use to help start thinking about it:

A fungible token has necessarily zero probability of economic gain or loss if exchanged for a like fungible token.

Non-fungible tokens have a necessarily greater than zero chance of economic gain or loss if exchanged for a like token.

To illustrate the difference, let’s look at an example. Imagine there exists a token that represents ownership of a house located at 123 Anywhere Street and another token that represents ownership of a house located at 456 Somewhere Else Street. For now, we can take for granted how ownership of a digital asset, the two tokens, can ever possibly represent ownership in real life of real world assets, it’s something we can leave to the lawyers to address. All we care about is that both of our tokens are independent and each represent a unique assets. If you held one token would you be ready to blindly exchange it for the other? Your answer should be it depends. You’ll probably want to know the valuation of the two houses, see where they are geographically located, how many bedrooms and bathrooms each have, the square footage of the space and whole host of other data points you’ll want.

There is a very good chance the two houses have entirely different valuations, so an exchange of one for the other does indeed have a probability greater than zero of economic losses or gain to both parties. Therefore, the house tokens will be non-fungible.

Figure 2-8. Let’s imagine a slightly different approach. Assume we issue 100 tokens that each represent equal ownership of a single house located at 123 Anywhere Boulevard. A single token represents a 1% equity or ownership stake in that house. If you own one of these tokens you own 1% of 123 Anywhere Boulevard. Are these 100 tokens fungible or non-fungible? Because each token represents the same thing and the exchange of one for the other results in absolutely zero probability of gain or loss, these tokens can be classified fungible. The exchange of one token that represents 1% ownership of the house for another token that represents 1% ownership of the house is a wash. These 100 tokens can be fungible tokens.
Figure 2-9. Pools
Figure 2-10. caption
Figure 2-11. A popular example of an NFT is CryptoKitties (http://CryptoKitties.co) where a non-fungible Ethereum token represents a particular virtual kitten. CryptoKitties provides a market where virtual kittens are minted, an NFT token is associated with that new kitten and users can buy, hold and sell these kittens. To buy a kitten, you purchase the non-fungible token that represents that specific kitten. Kittens can grow and their valuations (no kidding) can rise, with some kitten NFTs selling for thousands of dollars. NFTs represent a way to instrument digital collectibles and is a use case that many media companies that sell to a fan base will employ. If you’re a Taylor Swift fan, an NFT may a digital collectible that represents your attendance of a specific Taylor Swift concert, a badge you can proudly display or potentially sell.

Coding a non-fungible token

A non-fungible token is indivisible and not combinable, but is tradeable. Because of this, an amount property, like we had in our earlier Token class is not needed. A non-fungible token also needs a way to reference the underlying asset, whether it is a CryptoKitty or a house. We can create a non-fungible token class and this is what it might look like.

data class NonFungibleToken (var owner: String, val tokenIdentifier: String, val assetIdentifier: UUID = UUID.randomUUID())

The non-fungible token needs an owner, a token identifier and some means to reference the asset it represents. For the latter, we’ll use a random UUID as an arbitrary proxy identifier for the asset the token represents.

To create a new NFT that represents a kitten, we simply instantiate a NonFungibleToken class.

fun main() {

val kitten1 = NonFungibleToken(owner = “Issuer”, tokenIdentifier = “KITY”)

println(kitten1)

}

Output:

NonFungibleToken(owner=Issuer, tokenIdentifier=KITY, assetIdentifier=628f31d5-3bf6-4691-a11a-23b65823db04)

The asset identifier UUID can be used to associate a virtual kitten to the token and the token is now ready for use.

We should be able to transfer the token to another user. Our transferTo method looks like this:

infix fun transferTo(newOwner:String) {

owner = newOwner

}

And we’ll issue a new kitten NFT and transfer ownership of it to Bob

val kitten1 = NonFungibleToken(owner = “Issuer”, tokenIdentifier = “KITY”)

println(kitten1)

kitten1 transferTo “Bob”

println(kitten1)

Output:

NonFungibleToken(owner=Issuer, tokenIdentifier=KITY, assetIdentifier=721482b3-88c0-47cb-b36e-42e6de59bf0e)

NonFungibleToken(owner=Bob, tokenIdentifier=KITY, assetIdentifier=721482b3-88c0-47cb-b36e-42e6de59bf0e)

Is my token fungible? Non-fungible?

Making a decision early around the fungibility of your token is critical. Not only will your use case drive whether a token is fungible or non-fungible, but the two types may raise awareness around use cases you may have not thought of.

In the table below, we examine some examples of assets and their possibly fungibility use case. Note that these are not hard rules but guidelines to help elucidate the difference between a fungible token and an NFT.

Asset Fungibility Explanation
Cash Fungible The exchange of $1 for another $1 is economically indifferent.
Marked Bills NFT If specific currency bills need to be tracked (think drug enforcement) by their serial number then a NFT would be required.
Digital Cash Fungible The exchange of $1 in digital cash for another $1 in the same digital cash is economically indifferent.
Houses NFT The exchange of a token representing a house for a token representing a different house is not economically indifferent.
Cars NFT The exchange of a token representing a car for a token representing a different car is not economically indifferent.
Stablecoins Fungible The exchange of a single unit of a stablecoin for a different unit of the same stablecoin is economically indifferent.
Memorabilia & Collectibles NFT The exchange of a token representing collectibles or memorabilia, like a Ty Cobbs baseball card, for another token representing similar collectibles or memorabilia, like a different Ty Cobbs baseball, is not economically indifferent.
Tokenization of an asset Fungible If each token represents an equal interest in the asset the an exchange of one token for another token is fungible.

Separating issuer from owner

In our token examples, when a token was instantiated it was assigned an owner. We then added the ability to transfer the token to another owner, losing information about the first owner in the process. In most token use cases, the first owner is often the issuer of the token and who the issuer is information often needs to be retained throughout the life of a token. Why would an issuer be needed? Often, the token issued may have value that is derived from the issuer (i.e. their credit rating) and that information needs to be preserved as part and parcel of the token, while the sale and trading of the token, represented by the changes and transitions of the owner field, are distinct and independent of the issuer.

If keeping track of the issuer is needed, we can simply add the property, as seen below.

data class FungibleToken (override var owner:String , var amount: Int, override val tokenIdentifier: String,val issuer: String) : AbstractToken(owner,tokenIdentifier) {

fun transferTo(newOwner:String, transferAmount: Int) : FungibleToken {

.

.

return FungibleToken(owner = newOwner, amount = transferAmount, tokenIdentifier = tokenIdentifier, issuer = issuer)

.

.

.

}

data class NonFungibleToken (override var owner: String,

override val tokenIdentifier: String,

val assetIdentifier: UUID = UUID.randomUUID(),

val issuer: String) : AbstractToken(owner,tokenIdentifier) {

.

.

.

}

Refactoring our token classes

So far we’ve built out a Token class that represents fungible tokens and a NonFungibleToken class that helps us issue NFTs. The classes have been in somewhat of an ad hoc process and there is some overlapping features between the two that we can factor out into an interface or base class. Both tokens require an owner property and token identifier. So why not pull these out into a separate abstraction? In fact, over the next few pages we’ll perform several refactorings resulting in a clean token framework and the first step is to create a class hierarchy that looks like this:

Figure 2-12. We can extract out an AbstractToken class that contains the common properties between a fungible and non-fungible token, which are the owner and tokenIdentifier properties.

abstract class AbstractToken (open var owner: String, open val tokenIdentifier: String)

Next, we can rename our Token class to FungibleToken and subclass AbstractToken

data class FungibleToken (override var owner:String , var amount: Int, override val tokenIdentifier: String) : AbstractToken(owner,tokenIdentifier) {

fun transferTo(newOwner:String, transferAmount: Int) : FungibleToken {

if(amount > transferAmount) {

amount -= transferAmount

return FungibleToken(owner = newOwner, amount = transferAmount, tokenIdentifier = tokenIdentifier)

} else

throw Exception (“Insufficient tokens”)

}

infix fun combineWith (tokens:FungibleToken) : FungibleToken {

amount += tokens.amount

tokens.amount = 0

} else

throw Exception(“Mismatched token”)

}

}

We’ll also modify our NonFungibleToken to also subclass AbstractToken

data class NonFungibleToken (override var owner: String, override val tokenIdentifier: String, val assetIdentifier: UUID = UUID.randomUUID()) : AbstractToken(owner,tokenIdentifier) {

infix fun transferTo(newOwner:String) {

owner = newOwner

}

}

Completing this simple refactoring exercise should give you two token classes with a base abstract class. We have a few more refactoring steps complete to arrive at a comprehensive framework.

Typed token types

We assigned different token identifiers to differentiate types of tokens. These token identifiers are typed as string, which requires us to programmatically to check for matches. We can push this work off to the JVM by creating a static type for each token type. To do so we can create a base class called TokenType which wraps the tokenIdentifier string. We can then extend this class for each token type we wish to create.

The TokenType class below wraps the tokenIdentifier. We can remove tokenIdentifier from AbstractToken and shift it into TokenType

open class TokenType(val tokenIdentifier : String)

To create a new type of token, like LYL all we need to do is subclass TokenType and set the tokenIdentifier

class LoyalTokenType : TokenType(“LYL”)

Because the AbstractToken is missing token type information, we can genericize it to use TokenType

abstract class AbstractToken<T: TokenType> (open var owner: String)

This change requires to change our FungibleToken and NonFungibleToken classes and use the TokenType template generic. The changes to FungibleToken looks like:

data class FungibleToken<T:TokenType> (override var owner:String , var amount: Int) : AbstractToken<T>(owner) {

fun transferTo(newOwner:String, transferAmount: Int) : FungibleToken<T> {

if(amount > transferAmount) {

amount -= transferAmount

return FungibleToken<T>(owner = newOwner, amount = transferAmount)

} else

throw Exception (“Insufficient tokens”)

}

infix fun combineWith (tokens:FungibleToken<T>) : FungibleToken<T> {

amount += tokens.amount

tokens.amount = 0

}

}

Notice the conditional logic in combineWith has been removed. There is no longer a need to compare tokenIdentifiers. Putting it all together, we can create a token that represents cash using TokenType and CashType

class CashType : TokenType(“CASH”)

val cashTokens = FungibleToken<CashType>(“Issuer”,5000)

println(cashTokens)

Output:

FungibleToken(owner=Issuer, amount=5000)

Let’s illustrate the creation of two cash pools and move a token from one pool to another

val cashTokens = FungibleToken<CashType>(“Issuer”,5000)

println(cashTokens)

val cashTokens2 = FungibleToken<CashType>(“Issuer2”, 1000)

println(cashTokens combineWith cashTokens2)

Output:

FungibleToken(owner=Issuer, amount=5000)

FungibleToken(owner=Issuer, amount=6000)

We’ll create another type of token, called Libra and create cash and Libra tokens and see if we can move tokens between pools:

class LibraType : TokenType(“LIBRA”)

fun main() {

val cashTokens = FungibleToken<CashType>(“Issuer”,5000)

println(cashTokens)

val cashTokens2 = FungibleToken<CashType>(“Issuer2”, 1000)

println(cashTokens combineWith cashTokens2)

val libraTokens = FungibleToken<LibraType>(“Issuer”,5000)

println(libraTokens)

val ricksCash = cashTokens.transferTo(“Rick”,30)

libraTokens combineWith ricksCash

}

In trying to combine a CASH token type with LIBRA, we can see that IntelliJ will start complaining and places a red underlines beneath ricksCash in the last line of the code below:

Figure 2-13. We can also refactor our NonFungibleToken class to use TokenType.

The data class NonFungibleToken<T: TokenType> (override var owner: String, val assetIdentifier: UUID = UUID.randomUUID()) : AbstractToken<T>(owner) {

infix fun transferTo(newOwner:String) {

owner = newOwner

}

}

To create a CryptoKitty NFT using our new generics

class CryptoKittiesType : TokenType(“KITY”)

fun main() {

val nft = NonFungibleToken<CryptoKittiesType>(“Linda”)

println(nft)

}

Output

NonFungibleToken(owner=Linda, assetIdentifier=2f37c460-e57c-4479-87ec-e6b4350ec2f0)

Our token class framework should like this, where Libra, Cash and LYL are custom token types and Fungible and NonFungibleTokens are parameterized to type to TokenType

Figure 2-14. Figure caption

The Token SDK

If you have been reading from the beginning of the chapter then I’ve got good news for you, you should be fully prepared to understand the Corda Token SDK because what we’ve been building up till now is a very similar token framework. You’ll see many of the classes and concepts appear in the Corda Token SDK, although the SDK is richer and more extensive.

Developed by Roger Willis of R3, the Token SDK (or library) is a suite of classes that allow us to rapidly build token-based applications. Much of the work we’ve just done to incrementally construct a token class has direct parallels in the SDK. The SDK also includes flows and contracts we can use to issue and transfer tokens. We’ll build a token application using the token SDK in the next chapter.

Stablecoins: Low volatility tokens with fiat redeemability

As a society we use currency because it affords certain properties we can rely. Some of these properties include the currency being a medium of exchange, unit of account and store of value. Instead of bartering two assets, especially if these assets have different shelf lives and valuations, we can use currency as a medium of exchange and placeholder for value in a trade and as a unit of account we can enumerate, generally to some create detail, the value of an asset, like a gallon of milk, with a value like $4.35. Store of value, however, is unique and is deeply connected with the human psychological need for safety and preservation for the future. When we store value in fiat currencies we expect that value to remain, by and large, constant. That is, my $5 dollars should allow me to buy a gallon of milk today as well as a month from now. The implied expectation we as a society have around a currency is that its value remains stable. Clearly, there are fiat currencies that have experienced high degrees of instability, hyperinflation and devaluation, but most fiat currencies globally are generally stable or have a very low standard deviation of volatility.

Cryptocurrencies like Bitcoin and Ethereum take store of value and turn it on its head. Both cryptocurrencies are extremely volatile. Five dollars worth of Bitcoin might buy you milk today but might buy you a house next year, that’s how wildly volatile it is. While this might invite speculative investors, as a bedrock of store of value for society to rely on it is not. The chart below shows the volatility of Bitcoin often touching an astounding 15 standard deviations and Ethereum, while the US dollar, although volatile and often only episodically, is generally far more stable than Bitcoin and Ethereum.

Figure 2-15. Volatility of US dollar using DXY, note that the Y-axis is not standard deviation but just dollar value.

The need and desire for a cryptocurrency to be a stable store of value has led to the creation of stablecoins, where redeemable tokens represent and are pegged against a pool of cash. Typically a token’s value is made less volatile by allowing it to be redeemed for a single unit of fiat currency. The psychological impact of this redemption right, much like how the US dollar was once redeemable for gold, is theorized to help make a token’s value more stable.

Figure 2-16. A number of organizations have issued public stablecoins, including the Facebook famous Winklevoss twins and their Gemini Dollar (GUSD). Below is the price chart of the Gemini dollar and the green line shows that it is generally correlates well to the dollar.
Figure 2-17. Corda is an excellent choice for building token applications that have redemption capabilities. Corda can be used for issuing and managing tokens between multiple parties and free add ons Corda Settler allows for redemption settlement. Given Corda’s permissioned nature, the tokens would not trade publicly but between enterprises and organizations that typically also require store of value. However, unlike fiat currencies in the current banking world, tokens promise faster, potentially real-time, settlement opportunities and this is exactly what banks like JPMorgan Chase are doing with tokens, albeit on their own blockchain, and IVNO on the Corda chain, which we’ll touch upon next.

Enterprise Tokens

We are at the dawn of a token revolution and the enterprise world is taking notice.

Quorum & The JPMorgan Coin

One of JPMorgan’s (JPM)’s major banking functions is to courier dollars around the world, in the form of wires and remittances. JPM moves around $6 trillion a day, settling dollar transactions for a large percentage of global fiat movement. Creating friction for JPM is that due to a combination of regulation, risk management and legacy systems, the amount of a single wire is capped and the movement of a large amount of money requires multiple wires and on the receiving side, some diligence to reconstitute. To solve this problem, JPM created the JPM coin, a token that the bank and its institutional clients can use to settle trades. The JPMC is built on the Quorum blockchain, a fork of Ethereum with added features like data privacy and RAFT consensus.

Libra

In June of 2019, the much anticipated “Facebook coin” was launched. Known as Libra, and issued and managed by the Switzerland domiciled Libra Association, it is a token pegged to a weighted basket of currencies and runs on a custom-built permissioned blockchain. At the time of this writing, neither are in production. Given Facebook’s history with privacy, Libra may face challenges around what it will do with the data despite being just 1 out of 27 members in the Libra Association which consists of 26 other enterprises like MasterCard, PayPal, Spotify and eBay.

Walmart’s Token

In August of 2019, Walmart was awarded US Patent # 20190236564 for the creation of token that is pegged to a fiat currency. This sparked speculation (and I got calls from the US Capitol from those representing Arizona constituents) on what Wal-Mart might be planning. Interestingly, Walmart makes it clear that one of the objectives for issuing its own token is to gain further insights into their customer’s spending behavior and to better provide forecasts on purchasing habits. At the time of this writing, the technology stack Walmart would use is not known.

Figure 2-18. Figure caption

IVNO

IVNO is a UK-based firm that has built a token CorDapp where each token is backed by collateral.

In this chapter we introduce some core token concepts and quickly perused the token use case landscape. This will give you a solid appreciation of what tokens are, how they can be used and how to think about them from both a business and technical level. But we’re only scratching the surface, the groundswell of token use cases and applications of token semantics is in its early stages and the next few years we will see rapid growth and transformations in how tokens are used. In the next chapter we start to take pull what we learned in this chapter, roll up our sleeves and start producing CorDapps that are token aware.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.19.27.178