# WEB 3 - 101
Before diving deeper into the intricacies of Web 3 development, let’s explore what it is and why it exists.
First of all - what does number 3 mean? Likewise to people, who [have different generations](https://en.wikipedia.org/wiki/Generation#List_of_social_generations), the World Wide Web, or Internet in general, has also evolved through the years and can be loosely divided into the 3 “generations”:
- Web 1.0 - the first generation, roughly from 1991 to 2004. At this long forgotten age, the internet was slow, expensive, and dominated by static web pages. Most users were content consumers, with only a handful of content creators who created and hosted sites. JavaScript was at its infancy, media was rarely to be seen (due to internet speed and cost), and social media hadn't been invented yet. The Internet was highly decentralized and open to anyone. Everyone ran their own server or used one of the numerous hosting providers. Open protocols and standards were used for everything - HTTP, HTML, FTP, SMTP.
- Web 2.0 - the current generation, from 2004 till now. A massive paradigm shift started to happen around the 2000s. [The Matrix](https://en.wikipedia.org/wiki/The_Matrix) premiered in 1999, the Internet became faster and cheaper, and slowly but steadily started to spread into the lives of ordinary people. And as soon as people started to trickle in, business followed. More and more services were offered through the web, like payments, shopping, deliveries. Pages became more interactive and rich with media, but most importantly - users transitioned from just consuming content, to actively creating one. Social media boomed, smartphones flooded the market, and Web 2.0 began its explosive growth we are still seeing to this day.
At present day, the internet underpins every aspect of modern life, but with all of its usefulness comes a darker side. As it grew, it became more and more centralized. While this centralization brought a number of benefits, there are a number of problems as well. Digital ownership is one of them. As digital assets became ubiquitous, it became apparent that users don't really own them. Instead, ownership remained with centralized companies. Google can block access to your emails on Gmail any time it wants ([one example](https://www.businessinsider.com/terraria-google-youtube-gmail-play-2021-2)), or a game company can shut down a game server and destroy forever a game you once bought.
Another major problem is a loss of privacy. A new business model has emerged, where users “pay” for the services with their personal data, and often there are no real alternatives for them.
- Web 3.0 - the next generation. It’s still in its early stages, and no one knows for sure how it will eventually look, but several key aspects can already be outlined:
- Focus on decentralization and privacy. Shift digital ownership from companies to users.
- Immersive media. AR/VR as the next stage of media evolution.
- Semantic web - structure web data to pover all kinds of integrations, AI & Machine Learning.
In the scope of this guideline we’ll explore the first key aspect of Web 3.0 - how to build a service (game), in which digital assets are decentralized and owned by users.
## Building blocks of Web decentralization
As we already briefly discussed, the current Web is highly centralized, and mostly built using classical client-server architecture. Servers are usually owned and fully controlled by the companies. And all of these servers are often centralized even more, by being hosted on one of the clouds (AWS, Azure, GCP, ect). According to one report, 90% of mobile traffic goes to the clouds, which means a significant portion of the Internet is basically controlled by a handful of companies. But ways to reduce our reliance on central servers and shift the balance of power back to the users are already there, so let’s explore them.
The first decentralization revolution happened in file sharing, with the arrival of the (in)famous BitTorrent protocol. By being a p2p protocol, it’s truly decentralized, and allows data to be stored distributedly without any central authority (and sometimes without consent of a central authority, which caused a lot of drama, but that’s a story for another time). Ideas behind this protocol have been used in modern decentralized file storages like IPFS and FileCoin, we’ll come back to this later and explore it in more details.
The next revolution happened in the world of finance. For a long time transferring money required a central authority (banks), which would monitor, approve and execute these transfers. This has changed when the first cryptocurrency - Bitcoin - appeared. As already mentioned BitTorrent protocol, it also uses p2p communication, but instead of files it operates a transaction ledger, which is stored as a blockchain. Blockchain structure is needed to ensure that stored ledger cannot be altered, and at the same time to incentivize storage of this data. Unlike BitTorrent, Bitcoin network participants are rewarded for their services using a process called “mining”. This created a foundation for a new form of currency - digital currency (or cryptocurrency), with a unique property that it doesn’t need a central authority to function. Instead, users themselves maintain and operate it. And as with the previous decentralized system, BitTorrent, central authorities have issues with this.
Following the success of Bitcoin, other cryptocurrencies started to appear. The most important one is Ethereum, which took the concept of blockchain one step further and adapted it to store not just a transactions leger, but any kind of data, and, most importantly code (which is just another form of data). Basically, it turned out we can use it as a decentralized database transaction log. And if we have data and code living in the decentralized database, the only thing we lack to build a decentralized application is an ability to execute this code. So Ethereum did just that, and a Smart Contract was born. So let's dive deeper into the world of blockchains, smart contracts, and explore how we can build decentralized applications with them.
## Blockchain basics
Let's start with a brief overview of what blockchain and smart contracts are.
In classical Web 2.0 applications, you need 2 things to build an application backend: a database to store data and a server to execute your code. The same is true for the Web 3.0, but instead of a database we have a blockchain, and instead of a server we have smart contracts.
Blockchain itself is just a linked list (chain) of transactions. As a performance optimization, instead of linking individual transactions, they are grouped into blocks. Linking happens using hashes - each block contains the cryptographic hash of a previous block. Such a structure grants us an important property - we cannot modify an individual transaction inside a chain, since it would change its hash and invalidate all transactions after it. This makes it an ideal structure to store in a decentralized fashion, since everyone can quickly verify the integrity of a transaction on a chain (and of the entire chain).

Since we can only add new transactions to the chain, it serves as a decentralized transaction log. And if we have a [transaction log](https://en.wikipedia.org/wiki/Transaction_log), we basically have our database. Another good mental model is to think about this as a decentralized [event sourcing](Pattern: Event sourcing) pattern, where each transaction represents a separate event.
Due to the distributed nature of a blockchain, that has no single server which would manage a blockchain, a consensus mechanism is used to add new blocks, synchronize data between machines, and incentivize network participation. Several consensus mechanisms exist, we’ll discuss them in more detail later.
It’s important to remember that every transaction on blockchain is publicly visible, so sensitive data should be encrypted beforehand.
But how do we put transactions into a blockchain? That’s the purpose of a Blockchain Node. Everyone can set up their own node, connect to the p2p blockchain network, and post new transactions. Also, this node provides access to the current blockchain data.

So far we’ve explored how the backend layer of a dApp looks like, but what about the client side? Since we are using an API to communicate, we can use any kind of a client we use in the Web 2.0 - web, mobile, desktop, and even other servers. However, an important distinction lies with users.
In a traditional Web 2.0 application, each server owns the identities of his users, and fully in control over who can and can’t use its services. In blockchain, however, there are no such restrictions, and anyone can interact with it (there are [private blockchains](https://www.investopedia.com/terms/p/permissioned-blockchains.asp), but we’ll leave them out of scope).
But how do we perform authentication if there is no standard login/registration process? Instead, we use public key cryptography, where public key servers as a username, and private key is a loose equivalent of a password. The major distinction is that instead of a login procedure, in which the server verifies our credentials and grants as some form of an access token, users sign transactions with a private key. This means that there is no real [identification](https://en.wikipedia.org/wiki/Identification), only [authentication](https://en.wikipedia.org/wiki/Authentication) - this should be considered if you are building applications that require [KYC](https://en.wikipedia.org/wiki/Know_your_customer).
Another important implication of using private/public key pairs for auth, is that they cannot be easily memorized, like username/password pair. For this purpose, special applications called wallets are used. They store user’s key pairs and can sign transactions or provide them for other applications.
<div style="text-align:center">
<img src="https://i.imgur.com/p1K9AeG.png"/>
</div>
The one aspect we haven’t considered yet is infrastructure cost. In WEB 2.0, users pay for the provided service (directly with money or indirectly with their data, or both), and service providers pay for the infrastructure.
<div style="text-align:center">
<img src="https://i.imgur.com/b8hf6mq.png"/>
</div>
In a Web 3.0 model, users pay directly to the infrastructure provider (nodes running in the blockchain), bypassing the service provider.
<div style="text-align:center">
<img src="https://i.imgur.com/ADiQA56.png"/>
</div>
This has huge implications:
- Service providers can’t shut down services or restrict their usage, since they are deployed on blockchain and can’t be removed. This means the application will live forever (or at least until the blockchain network is alive).
- A new monetization model should be used for such services, since users don’t pay directly to service providers. For example, a fee can be coded into a smart contract for performing certain actions.
- Since users should pay for the infrastructure, there’s no free lunch (this is usually true for Web 2.0 as well, but it’s often not obvious for ordinary users). Service providers can cover some cost or provide a credit to simplify onboarding, but ultimately users would have to pay.
But how do users pay? Since it’s a blockchain, they can’t pay directly with a credit card - in this way it will be tied to a central authority and not really decentralized. A solution is to use a decentralized currency - cryptocurrency. Each blockchain has its own currency, which is used for payments inside of it.
Whenever a user wants to perform an action on a blockchain by calling a smart contract, it should always pay an infrastructure cost, and optionally a service cost to the service provider.
<div style="text-align:center">
<img src="https://i.imgur.com/IzECLKZ.png"/>
</div>
This infrastructure cost, often called “gas”, usually consists of 2 parts:
- Computational cost - to cover computational power needed to add a transaction into a blockchain.
- Storage cost - to cover additional storage requirements necessary for each transaction.
However, the question still remains how users can obtain cryptocurrency tokens in the first place. One option is to buy it from other users who already own it by using traditional money or another cryptocurrency. There are exchanges which provide such kind of functionality, e.g. [Binance](https://www.binance.com/en). But this will work only if there is already an existing supply of tokens already in circulation.
In order to create and grow this supply the blockchain consensus mechanism is used. Earlier, we mentioned that it is used to incentivize blockchain network participation, but how exactly does it happen? Each node that processes transactions receives a reward for its work:
<div style="text-align:center">
<b>reward = infrastructureCostReward + coinbaseReward</b>
</div>
where:
- infrastructureCostReward - share of infrastructure cost paid for the transactions by the users
- coinbaseReward - new cryptocurrency token created specifically to reward processing nodes
This means each time a transaction is processed a small amount of cryptocurrency is created, so the amount of cryptocurrency in circulation grows over time (of course some amount of tokens should be created to bootstrap the network, e. g. by using [ICO](https://www.investopedia.com/terms/i/initial-coin-offering-ico.asp)).
At a present day, two consensus mechanisms are commonly used:
- [Proof-of-work](https://www.investopedia.com/terms/p/proof-work.asp) - original consensus mechanism, which is used by Bitcoin and Ethereum. It’s highly criticized for its inefficiency - processing of new transactions requires “mining”, which is a highly computationally intensive process. Because of this, graphic cards became an endangered species. Another disadvantage - cost of transactions is very high and processing speed is also quite slow.
- [Proof-of-stake](https://www.investopedia.com/terms/p/proof-stake-pos.asp) - newer consensus mechanism, which doesn’t require significant processing power (and graphic cards). Processing of transactions is usually called “validation”. Newer chains, like NEAR, use it. Ethereum is also currently in a process of switching to this model. Transactions are usually much cheaper and processing speed is faster.
At this point, we should have enough knowledge to proceed to the next chapter - choosing the best blockchain to build dApps.
## Choosing the right blockchain
There are a lot of blockchains out there and it might be hard to choose the most suitable one for your needs. First of all, we should define the most important characteristic for a chain:
- Consensus algorithm - by now Proof-of-work proved to be too inefficient and not suitable for high-scale applications. Proof-of-stake seems like a much better choice for now. Other alternatives exist, but they are less explored and tried in practice.
- Transaction/Storage cost - cheaper cost directly benefits users (recall, that users will pay for it).
- Transaction speed - faster transactions processing time means better user experience.
- Scalability - whether a network is designed to support a large number of transactions. If not, transaction speed/cost may grow out of control over time.
- Development experience - most importantly, what language we’ll use to write our smart contracts. Ethereum popularized [Solidity](https://docs.soliditylang.org/en/v0.8.12/) as a programming language of choice for contracts. Several newer chains, like NEAR, chose Rust, which is a more mature general-purpose programming language.
Historically, the first blockchain to introduce smart contracts was Ethereum. However, as the number of users grew, transaction speed and cost skyrocketed, and it became apparent that it couldn't handle the demand. So, a number of [scaling solutions](https://ethereum.org/en/developers/docs/scaling/) appeared - [layer 2 chains](https://ethereum.org/en/developers/docs/scaling/#layer-2-scaling), [sidechains](https://ethereum.org/en/developers/docs/scaling/sidechains/), and [plazma chains](https://ethereum.org/en/developers/docs/scaling/plasma/). However, they all use some kind of workarounds with their own unique drawbacks. Ethereum tries to fix the core problem and redesign its network - like switching to a Proof-of-stake consensus, which is ongoing for quite a long time, but exact timeline when all of the problems will be fixed is very unclear.
Meanwhile, a new generation of blockchains started to appear. They learned from the Etherium mistakes, and designed them from ground-up to be fast, cheap and scalable.
Choosing the right one is by no means an easy task, but for us we found the [NEAR](https://near.org/) blockchain to be an ideal solution, because of the following properties:
- Transactions are cheap and very fast.
- Designed to be extremely scalable from the beginning. This means we can count that transaction cost and speed will remain stable in the future.
- Uses Proof-of-stake consensus mechanism - so no hated “mining” is needed.
- Rust is used as a primary programming language. Since it’s [a popular language](https://insights.stackoverflow.com/survey/2021#most-popular-technologies-language-prof) (and [one of the most loved](https://insights.stackoverflow.com/survey/2021#most-loved-dreaded-and-wanted-language-love-dread)), it’s much easier to learn and find developers on the market.
All of the further sections will use NEAR as an underlying blockchain, so before we jump into the intricacies of the Web 3.0 migration, we should take a closer look at it first.
## NEAR Protocol
For the beginners, it’s always better to start with [documentation](https://docs.near.org/docs/concepts/new-to-near), and NEAR has an excellent one. Here, we only focus on basic concepts which are necessary to understand later chapters, so an entire guideline could be understood without prior NEAR knowledge.
## Accounts & Transactions
NEARs account system is very powerful and differs substantially from other blockchains, like Bitcoin or Ethereum. Instead of identifying users by their public/private key pairs, it defines accounts as first-class entities. This has a few important implications:
- Instead of public keys, users can use readable account names.
- Multiple key pairs with [different permissions](https://docs.near.org/docs/concepts/account#access-keys) can be used. This provides a better security model for users, since loss of one key pair doesn’t compromise an entire account and has a quite limited impact.
- Hierarchical accounts structure is supported. This is useful if we want to manage multiple smart contracts under one parent account.
- Accounts/public keys are created using transactions, since they are stored on the blockchain.
More information on NEAR accounts can be [found in the docs](https://docs.near.org/docs/concepts/account#accounts-and-contracts).
But an account by itself won’t get us anywhere, its [transactions](https://docs.near.org/docs/concepts/transaction) that make things happen. In NEAR, we have only one transaction type, but the transaction itself may have different actions included. For most practical purposes, transactions will have a single action included, so for simplicity we’ll use “action” and “transaction” terms interchangeably further down the road. Each transaction always has sender and receiver accounts (and it is cryptographically signed by the sender’s key). The following transaction (action) types are supported:
- CreateAccount/DeleteAccount, AddKey/DeleteKey - accounts and key management transactions.
- Transfer - send NEAR tokens from one account to another. The basic command of any blockchain.
- Stake - needed to become a validator in a Proof-of-Stake blockchain network. We won’t touch this topic in this guideline, more information [can be found here](https://docs.near.org/docs/develop/node/validator/staking-and-delegation).
- DeployContract - deploy a smart contract to a given account. An important thing to remember - one account can hold only one contract, so the contract is uniquely identified by the account name. If we issue this transaction to an account which already has a deployed contract, a contract update will be triggered.
- FunctionCall - the most important action on the blockchain, it allows us to call a function of a smart contract.
Smart Contracts on NEAR are written in Rust, and compiled into [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) (technically, [AssemblyScirpt](https://www.assemblyscript.org/) is also supported, but it’s not yet production ready). Each contract has one or more methods that can be called via a FunctionCall transaction. Methods may have arguments provided, so each smart contract call includes the following payload: contract_account_id, contract_method_name, arguments.
There are 2 ways to call a method on a smart contract:
1. Issue a FunctionCall transaction. This will create a new transaction on a blockchain which may modify a contract state.
2. Make a smart contract view call. NEAR blockchain [RPC nodes](https://docs.near.org/docs/develop/node/intro/node-types#rpc-node) provide a special API that allow execution of methods that do not modify contract state (readonly methods).
The second method should always be used whenever possible since it doesn’t incur any transaction cost (of course, there is some cost of running a node, but it’s still much cheaper than a transaction; public nodes are available which can be used free of charge). Also, since there’s no transactions, we don’t need an account to make a view call, which is quite useful for building client-side applications
## Gas and Storage
As we already discussed, users should pay computational costs for each transaction. This cost is called “gas” and is measured in [gas units](https://docs.near.org/docs/concepts/gas) (this is an established term in the blockchain world). Each time a transaction is posted, an amount of gas is attached to it to cover the cost. For simple transactions, gas can be calculated ahead of time to attach an exact amount. For FunctionCall transactions, however, exact cost is impossible to automatically calculate beforehand, so the usual approach is to attach a large enough amount of gas to cover the cost, and any excess will get automatically refunded.
<div style="text-align:center">
<img src=https://i.imgur.com/m9FcNp7.png/>
</div>
But why do we need separate gas units, why not just pay directly with NEAR tokens? It’s necessary to accommodate for changing infrastructure costs - as the network evolves over time, cost of gas units may change, but the amount of gas required for a transaction will remain constant.
However, computational cost is not everything - most smart contracts also need storage. The storage cost in NEAR is quite different from gas.
First of all, it’s not cheap - while gas is very cheap and its cost will be almost unnoticeable by the users, storage is very expensive. As a consequence, the storage budget should be carefully calculated and only necessary data stored on the blockchain. Any auxiliary data (that is not necessary to the contract operations) should be stored off-chain (possible solutions will be covered in later chapters).
The second important difference - storage is not buyed, but leased (in NEAR, it’s called staking). When a smart contract wants to store some data, storage cost is computed and the appropriate amount of NEAR tokens is “locked” on the account. When data is removed, tokens are unlocked. And unlike gas, these tokens are locked on the smart contract’s account, so the user doesn’t directly pay for it.
But what if we want users to pay for the storage (or just pay some fee for using a smart contract)? So far, the only way we’ve seen to transfer a token is a Transfer transaction. It turns out, a FunctionCall transaction also allows us to transfer tokens alongside the call (this is called a deposit). Smart Contract can verify that an appropriate amount of tokens has been attached, and refuse to perform any actions if there’s not enough (and refund any excess of tokens attached).
In combination, gas fee and deposit attachments enable creation of contracts that need zero cost from developers to support and can live on blockchain forever. Even more, 30% of gas fees spent on the contract execution will go to a contract’s account iself (read more [here](https://near.org/blog/near-protocol-economics/#:~:text=a%20new%20entity.-,Contract%20rewards,-As%20one%20of)), so just by being used it will bring some income. To be fair, due to the cheap gas cost this will make a significant impact only for most popular and often-called contracts, but it’s nice to have such an option nonetheless.
One last gotcha about storage - remember that smart contracts themselves are also just a code stored on a blockchain, so a DeployContract transaction will also incur storage fees. Since smart contracts code can be quite big, it’s important to optimize their size. A few tips on this:
- Don’t build Rust code on Windows, it produces quite big output. Use WSL or build on other OSes.
- Optimize smart contracts code for size - [more info here](https://www.near-sdk.io/reducing-contract-size/examples).
More details on the storage model can be [found in the docs](https://docs.near.org/docs/concepts/storage-staking).
## Gas and Storage
As we already discussed, users should pay computational costs for each transaction. This cost is called “gas” and is measured in gas units (this is an established term in the blockchain world). Each time a transaction is posted, an amount of gas is attached to it to cover the cost. For simple transactions, gas can be calculated ahead of time to attach an exact amount. For FunctionCall transactions, however, exact cost is impossible to automatically calculate beforehand, so the usual approach is to attach a large enough amount of gas to cover the cost, and any excess will get automatically refunded.
<div style="text-align:center">
<img src="https://i.imgur.com/t0aVl09.png"/>
</div>
But why do we need separate gas units, why not just pay directly with NEAR tokens? It’s necessary to accommodate for changing infrastructure costs - as the network evolves over time, cost of gas units may change, but the amount of gas required for a transaction will remain constant.
However, computational cost is not everything - most smart contracts also need storage. The storage cost in NEAR is quite different from gas.
First of all, it’s not cheap - while gas is very cheap and its cost will be almost unnoticeable by the users, storage is very expensive. As a consequence, the storage budget should be carefully calculated and only necessary data stored on the blockchain. Any auxiliary data (that is not necessary to the contract operations) should be stored off-chain (possible solutions will be covered in later chapters).
The second important difference - storage is not buyed, but leased (in NEAR, it’s called staking). When a smart contract wants to store some data, storage cost is computed and the appropriate amount of NEAR tokens is “locked” on the account. When data is removed, tokens are unlocked. And unlike gas, these tokens are locked on the smart contract’s account, so the user doesn’t directly pay for it.
But what if we want users to pay for the storage (or just pay some fee for using a smart contract)? So far, the only way we’ve seen to transfer a token is a Transfer transaction. It turns out, a FunctionCall transaction also allows us to transfer tokens alongside the call (this is called a deposit). Smart Contract can verify that an appropriate amount of tokens has been attached, and refuse to perform any actions if there’s not enough (and refund any excess of tokens attached).
In combination, gas fee and deposit attachments enable creation of contracts that need zero cost from developers to support and can live on blockchain forever. Even more, 30% of gas fees spent on the contract execution will go to a contract’s account iself (read more [here](https://near.org/blog/near-protocol-economics/#:~:text=a%20new%20entity.-,Contract%20rewards,-As%20one%20of)), so just by being used it will bring some income. To be fair, due to the cheap gas cost this will make a significant impact only for most popular and often-called contracts, but it’s nice to have such an option nonetheless.
One last gotcha about storage - remember that smart contracts themselves are also just a code stored on a blockchain, so a DeployContract transaction will also incur storage fees. Since smart contracts code can be quite big, it’s important to optimize their size. A few tips on this:
Don’t build Rust code on Windows, it produces quite big output. Use WSL or build on other OSes.
Optimize smart contracts code for size - [more info here](https://www.near-sdk.io/reducing-contract-size/examples).
More details on the storage model can be [found in the docs](https://docs.near.org/docs/concepts/storage-staking).
## Clients Integration
So far, we’ve discussed how to call smart contracts in a client-agnostic way. However, in the real world, calls we’ll be performed from a client side - like web, mobile or a desktop application.
As we’ve learned from previous chapters, each transaction should be signed using a key. And since keys are managed by a wallet, each application should integrate with it. At the time of this writing, there’s only one officially supported [NEAR Wallet](https://wallet.near.org/). It is a web application, so integration happens using HTTP redirects. This is relatively straightforward to do in web applications (JavaScript SDK is available), but for mobile or desktop applications it may require deep linking or other more advanced approaches.
The general flow for transactions signing looks like this:
<div style="text-align:center">
<img src="https://i.imgur.com/5a1QUVG.png">
</div>
Each time we want to post a transaction, the client redirects the user to a wallet, where the transaction is approved and wallet returns a signed transaction back to the client (via redirect). This is a quite secure way of signing, since the private key is not exposed to the client, but constant redirects might quickly get annoying for users, especially if we just want to call smart contract functions that incur only small gas fees. That’s why NEAR introduced [two types of access keys](https://docs.near.org/docs/concepts/account#access-keys) - full keys and functional call keys. Full access keys, as the name implies, can be used to sign any types of transactions. Functional call keys, on the other hand, aim to solve this UX problem. They are tied to a specific contract, and have a budget for gas fees. Such a key can’t be used to sign transactions that transfers NEAR tokens (payable transactions), and can only be used to cover gas fees, that’s why it’s not so security-critical and can be stored on the client. Because of this, we can create a simplified signing flow for non-payable transactions. First of all, a login flow to obtain a Functional Call key is used.
<div style="text-align:center">
<img src="https://i.imgur.com/f8NxHRe.png"/>
</div>
The client generates a new key pair and asks a wallet to add it as a functional call key for a given contract. After this, a login session is established and considered alive until the client has the generated key pair.
To provide the best user experience usage of both keys is combined - type of singing is determined based on a transaction type (payable or non-payable). In case of a payable transaction, flow with wallet redirection is used, otherwise simplified local signing flow (using a stored function call key) is applied:
<div style="text-align:center">
<img src="https://i.imgur.com/dtHIh48.png"/>
</div>
It’s important to note that it’s possible to generate a Full Access key using the same key addition flow as for the Functional Call key, but this is very dangerous since compromise of such key will give full control over an account. Applications that want to work with Full Key directly should be designed with extreme care, especially in the matters of security.
## Cross-contracts calls
Throughout this section, we’ve discussed how to call a smart contract from a client. But a single smart contract can only take us so far. The true power is achieved when smart contracts are working in concert and communicating with each other. To achieve this, NEAR provides cross-contract calls functionality, which allows one contract to call methods from another contract. The general flow looks like this:
<div style="text-align:center">
<img src="https://i.imgur.com/hYybtnn.png"/>
</div>
Looks simple enough, but there are few gotchas:
- In order to provide a call status (success or failure) and a return value to the calling contract, a callback method should be called, so there’s no single activation of ContractA. Insead, an entry method is called first by the user, and then a callback is invoked in response to cross-contract call completion.
- Transaction status is determined by the success or failure of a first method call. For example, if a ContractB.methodB or ContractA.methodACb call fails, the transaction will still be considered successful. This means that to ensure proper rollbacks in case of expected failures, custom rollback code must be written in the ContractA.methodACb, and the callback method itself must not fail at all. Otherwise, smart contract state might be left inconsistent.
- Cross-contract calls must have gas attached by the calling contract. Total available gas is attached to a transaction by a calling user, and distributed inside the call chain by contracts. For example, if 15TGas are attached by the user, ContractA may reserve 5TGas for itself and pass the rest to ContractB. All unspent gas will be refunded back to the user.
<div style="text-align:center">
<img src="https://i.imgur.com/ajLfB3p.png"/>
</div>
- NEAR tokens can also be attached to cross contract calls, but they work differently from the gas. Attached deposit is taken directly from the predecessor account. It means even if a user hasn’t attached any deposit, a contract still can attach tokens, which will be taken from its account. Also, since cross-contract call failure doesn’t mean transaction failure, there are no automatic refunds. All refunds should be done explicitly in the rollback code.
<div style="text-align:center">
<img src="https://i.imgur.com/ImZJQea.png"/>
</div>
A few notes on failure modes - since smart contracts run on a decentralized environment, which means they are executed on multiple machines and there is no single point of failure, they won’t fail because of environmental issues (e.g. because a machine suddenly lost power or network connectivity). The only possible failures come from the code itself, so they can be predicted and proper failover code added.
In general, cross-contract call graphs can be quite complex (one contract may call multiple contracts and even perform some conditional calls selection). The only limiting factor is the amount of gas attached, and there is a hard cap defined by the network of how many gas transactions may have (this is necessary to prevent any kind of DoS attacks on the Network and keep contracts complexity within reasonable bounds).
## Data Structures, Indexers and Events
We’ve already discussed the storage model on NEAR, but only in abstract terms, without bringing the exact structure, so it’s time to dive a bit deeper.
Natively, NEAR smart contracts store data as key-value pairs. This is quite limiting, since even simplest applications usually need more advanced data structures. To help in development, NEAR provides [SDK for smart contracts](https://github.com/near/near-sdk-rs), which includes data structures [like vectors, sets and maps](https://docs.near.org/ru/docs/concepts/data-storage#rust-collection-types). While they are very useful, it’s important to remember a few things about them:
- Ultimately, they are stored as binary values, which means it takes some gas to serialize and deserialize them. Also, different operations cost different amounts of gas ([complexity table](https://docs.near.org/docs/concepts/data-storage#big-o-notation-1)). Because of this, careful choice of data structures is very important. Moving to a different data structure later will not be easy and would probably require data migration.
- While very useful, vectors, maps and sets won’t match the flexibility and power of classical relational databases. Even implementations of simple filtering and searching might be quite complex and require a lot of gas to execute, especially if multiple entities with relations between them are involved.
- They are limited to a single contract. If data from multiple contracts is required, aggregation should be performed using cross-contract calls or on a client side, which is quite expensive in terms of gas and time.
To support more complex data retrieval scenarios, smart contract data should be put in a more appropriate store, like a relational database. [Indexers](https://docs.near.org/ru/docs/concepts/indexer) are used to achieve this. In a nutshell, indexer is just a special kind of blockchain node that processes incoming transactions and puts relevant data into a database. Collected data can be exposed to a client using a simple API server (e.g. REST or GraphQL).
<div style="text-align:center">
<img src="https://i.imgur.com/Zm86TTQ.png"/>
</div>
In order to simplify creation of indexers, [NEAR Indexer Framework](https://docs.near.org/ru/docs/tutorials/near-indexer) has been created. However, even with a framework available, extracting data from a transaction may not be an easy task, since each smart contract has its unique structure and data storage model. To simplify this process, smart contracts can write structured information about outcome into the logs (e.g. in the JSON format). Each smart contract can use its own format for such logs, but the general format has been standardized as [Events](https://nomicon.io/Standards/EventsFormat.
Such architecture is very similar to Event Sourcing, where blockchain stores events (transactions), and they are materialized to a relational database using an indexer. This means the same drawbacks also apply. For instance, a client should be designed to accommodate indexing delay, which may take a few seconds.
As an alternative to building your own indexer with a database and an API server, [The Graph](https://thegraph.com/en/) can be used instead, which currently has [NEAR support in beta](https://thegraph.com/docs/en/supported-networks/near/). It works using the Indexer-as-a-Service model, and even has decentralized indexing implementation.
## Development tools
By now, we should be familiar with necessary concepts to start developing WEB 3.0 applications, so let’s explore the development tools available.
First of all, we need a development and testing environment. Of course, we could theoraticaly perform development and testing on the main blockchain network, but this would not be cheap. For this reason, NEAR provides [several networks](https://docs.near.org/ru/docs/concepts/networks) that can be used during development:
- testnet - public NEAR network which is identical to mainnet and can be used for free.
- localnet - you can deploy your personal NEAR network on your own environment. Because it’s owned by you, data and code can be kept private during development. More info on how you can run your own node can be found [here](https://docs.near.org/ru/docs/tools/kurtosis-localnet). Alternatively, you can bootstrap an entire testing infrastructure in Docker on your local machine using Kurtosis - guide is [here](https://docs.near.org/ru/docs/develop/node/validator/running-a-node).
- sandbox - you can start your own sandbox node on your local or build machine to perform e2e testing. More info [here](https://docs.near.org/ru/docs/develop/contracts/sandbox).
Once we’ve chosen a network to use, we need a way to interact with it. Of course, transactions can be constructed manually and posted into [node’s API](https://docs.near.org/ru/docs/api/rpc). But [this is tedious](https://docs.near.org/ru/docs/tutorials/create-transactions#low-level----create-a-transaction) and isn’t fun at all. That’s why, NEAR [provides CLI](https://docs.near.org/ru/docs/tools/near-cli) which automates all of the necessary actions. It can be used locally for development purposes or on build machines for CI/CD scenarios.
In order to manage accounts on the NEAR network, [Wallet](https://docs.near.org/ru/docs/tools/near-wallet) can be used. It can show an effective account balance and active keys.
<div style="text-align:center">
<img src="https://i.imgur.com/Wttb67P.png"/>
</div>
Where “Reserved for storage” are tokens locked by a smart contract to cover current storage requirements, and “Reserved for transactions” represents the amount of tokens locked to cover gas cost by Functional Call keys.
Currently, there’s no UI to connect sub-accounts into a wallet. Instead, they should be imported via a specially construced direct link - https://wallet.testnet.near.org/auto-import-secret-key#YOUR_ACCOUNT_ID/YOUR_PRIVATE_KEY (you should provide a private key of a full access key for the account in question, so make sure this link is used securely).
Last, but not least, blockchain transactions can be viewed using NEAR Explorer. It provides insights into transaction execution and outcome. Let’s look at one example.
First of all, we can see general transaction information - sender, receiver, status. After this, we can see gas usage information:
- Attached gas - total gas provided for the transaction.
- Gas used - actual gas spend.
- Transaction fee - gas used multiplied to current gas price, shows an actual cost of a transaction in NEAR tokens.
Also, Deposit Value shows the amount of NEAR tokens transferred from sender to receiver.
<div style="text-align:center">
<img src="https://i.imgur.com/Nb6Kxmk.png"/>
</div>
Below this, we can inspect transaction actions (recall, that transactions may have multiple actions). In this case, we have a single FunctionCall action with arguments:
<div style="text-align:center">
<img src="https://i.imgur.com/N6Bna2Z.png">
</div>
At the end, transaction execution details, including token transfers, logs, cross-contract calls and gas refunds are provided. One thing that we haven’t covered yet is shown here - [receipts](https://docs.near.org/ru/docs/concepts/transaction#receipt). For most practical purposes they are just a transaction implementation detail. They are quite useful in a transaction explorer to understand how a transaction was executed, but aren’t really relevant outside of it.
<div style="text-align:center">
<img src="https://i.imgur.com/xeI0hOa.png">
</div>
## Contract upgrades
During the development, and sometimes even in production, updates to a contract’s code (or even data) are needed. That’s why different contract upgrades mechanisms have been created.
During the local development, we can just recreate a smart contract’s account each time we deploy a contract ([dev-deploy](https://docs.near.org/ru/docs/tools/near-cli#near-dev-deploy) command in NEAR CLI exists for this). With such an approach, contract data will be purged each time a contract is redeployed. More info [here](https://www.near-sdk.io/upgrading/prototyping).
However, once we move to a more stable environment, like testing or production, more sophisticated methods are needed. Redeployment of code is quite simple - we just issue another DeployContract transaction, and NEAR will handle the rest. The biggest challenge is to migrate contract state - [several approaches are possible](https://www.near-sdk.io/upgrading/production-basics), but all of them involve some kind of migration code.
But we can take our upgrade strategy one step further. In described strategies, developers are fully in control of code upgrades. This is fine for many applications, but it requires some level of trust between users and developers, since malicious changes could be made at any moment and without user’s consent (as it [sometimes happens](https://www.bleepingcomputer.com/news/security/dev-corrupts-npm-libs-colors-and-faker-breaking-thousands-of-apps/) in npm world). To solve this, a contract updates process itself can also be decentralized - this is called [DAO-Governed Updates](https://www.near-sdk.io/upgrading/via-dao-vote). Exact strategy may vary, but the basic idea is that contract update code is implemented in a smart contract itself, and a Full Access key to the contract account is removed from a blockchain (via DeleteKey transaction). In this way, an update strategy is transparent to everyone and cannot be changed by developers at will.
## Further reading
For a deep dive into NEAR, the following links will be useful:
- NEAR docs
- Rust Smart Contract docs
- Smart Contract quick start guide
- NEAR Protocol Specification
- How to build dApp on NEAR
## WEB 3.0 Economics
With technological decentralization also came economical decentralization. It stands on 3 pillars - Non-Fungible tokens (NFTs), Fungible tokens (FTs) and Decentralized Finance (DeFi).
## Non-Fungible Tokens
At the heart of the new Web 3 economy lies [Non-Fungible token](https://en.wikipedia.org/wiki/Non-fungible_token) (NFT). In a nutshell, it’s a way to represent digital ownership in a decentralized way. From a technical perspective, it’s just a piece of data on a blockchain. The simplest case of such data is just a (token_id, accoount_id) tuple, where token_id uniquely identifies an asset, and account_id identifies an owner. A smart contract that owns this data defines a set of allowed operations - like creation of a new token (minting) or transfer of a token to another account. An exact set of allowed operations is defined in an NFT standard. Different blockchains have different standards, NEAR NFT Standard is available [here](https://nomicon.io/Standards/NonFungibleToken/).
Because NFTs are tied to a specific contract, they mostly make sense only in scope of this contract, and subsequently they are tied to a specific dApp. It’s possible to implement transfer of NFTs between contracts, but there’s no standard way to do this.
What digital asset is hiding behind a token_id is up to the smart contract to decide. There are few common ways how to handle this:
- Store an asset itself in a smart contract alongside the ownership information. This is the most straightforward way, but often is not feasible since storage cost is quite high and many types of digital assets, especially media, are quite big.
<div style="text-align:center">
<img src="https://i.imgur.com/4TpdnSf.png"/>
</div>
- Store token data off-chain. Such an approach solves storage cost problems, but requires some level of trust to guarantee that data in the off-chain storage won’t be changed or removed.
<div style="text-align:center">
<img src="https://i.imgur.com/qbpHd5R.png"/>
</div>
- Store asset’s metadata and hash on chain, and an asset itself on some off-chan storage. Storing an asset’s hash on a chain guarantees data integrity and immutability. On-chain metadata usually includes basic token information, like title, description and media url. It’s required to quickly identify an asset without downloading it from the storage. This is the most popular approach to handle NFT’s since it combines the best of 2 previous approaches - token is immutable and storage cost is cheap (exact cost depends on the storage solution, but it usually several orders of magnitude cheaper than an on-chain storage)
<div style="text-align:center">
<img src="https://i.imgur.com/vUU9PdB.png"/>
</div>
Choosing the right off-chain storage also can be a challenge, in general they can be divided into 2 buckets:
- Centralized storages - traditional Web 2 storage solutions, like relational databases or blob storages. While suitable for some applications, this means NFTs can be destroyed if a central server goes offline, so they aren’t the most popular in the Web 3 world.
- Decentralized storages. As we already mentioned, BitTorrent protocol is one of the first examples of such decentralized storage solutions, but in recent years more advanced solutions have appeared - like [IPFS](https://ipfs.io/), [FileCoin](https://filecoin.io/) and [Arweawe](https://filecoin.io/). Such solutions are a preferred method to store digital assets, since they are cheap and decentralized, so no-one can destroy or alter NFT assets.
In addition to the NFT standard, NEAR also provides [its implementation](https://docs.rs/near-contract-standards/4.0.0-pre.6/near_contract_standards/non_fungible_token/index.html), which can be used by Smart Contract developers to implement NFTs in their smart contract. Implementation itself doesn’t dictate assets storage model, so it’s up to a developer to decide how and where it will be stored.
## Fungible Tokens
NFTs changed digital assets ownership model, but by itself they are not enough to build a full digital economy. In the simplest model, NFTs can be sold and bought using main blockchain currency (e.g. NEAR tokens), but this is quite limiting since circulation and price of such tokens is dictated by the blockchain itself. What if, instead of relying on blockchain currency, applications could create their own? For exactly this reason, Fungible Tokens (FT) have been created.
Similarly to NFTs, fungible tokens are also just a piece of data stored in a smart contract, but instead of storing unique token ids, an amount of tokens held by an account is stored.
<div style="text-align:center">
<img src="https://i.imgur.com/GG3620K.png"/>
</div>
Smart Contracts can define allowed operations - like transfer or payment using this token. [NEAR defines a standard](https://nomicon.io/Standards/FungibleToken/Core) for fungible tokens and provides a [default implementation](default implementation).
Since an application is fully in control over emission and circulation of such tokens, a full fledged application economy can be created. For example, users can earn FTs for performing actions, and spend them to buy or mint new NFTs.
Another exciting option is creation of [Decentralized Autonomous Organizations](https://near.org/ru/use-cases/dao/) (DAOs), in which FTs can be used as a membership (or governance) tool. In such scenarios, tokens are awarded to members and can be used to vote on decisions or participate in community events.
But we can push our tokens even further, by tying them to other cryptocurrencies and giving them a real-life monetary value. That’s where [Decentralized Finance](https://www.investopedia.com/decentralized-finance-defi-5113835) (DeFi), and especially [Decentralized Exchanges](https://en.wikipedia.org/wiki/Decentralized_exchange) (DEX) come into play. We won’t go into details here, but at the core a [liquidity pool](https://academy.binance.com/en/articles/what-are-liquidity-pools-in-defi) for a Fungible Token can be created on DEX, which allows trades of this token for other tokens or [stablecoins](https://en.wikipedia.org/wiki/Stablecoin). This opens the door for a new gaming model - [Play-to-Earn](https://en.wikipedia.org/wiki/Blockchain_game), where players can earn real-life money just by playing a game.
In the next chapters, we’ll explore how to bring an open Web 3 economy into an existing mobile game by converting in-game assets into NFTs, and then how to introduce FTs to create a full tokenomics and pave the way for a play-to-earn gaming model.