NEAR Protocol
For the beginners, it’s always better to start with documentation, 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
NEAR's 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 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.
But an account by itself won’t get us anywhere, its transactions 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.
- 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 or JavaScript, and compiled into WebAssembly. 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: account id, method name, and arguments.
There are 2 ways to call a method on a smart contract:
- Issue a FunctionCall transaction. This will create a new transaction on a blockchain which may modify a contract state.
- Make a smart contract view call. NEAR blockchain RPC nodes 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 (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.
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 bought, 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 Contracts 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 itself (read more here), 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.
More details on the storage model can be found in the docs.