During Hack the Rainbow, two of the NEAR Collective's team members - Matt Lockyer and Sherif Abushadi - gave a webinar on NEAR accounts and Key Registration. They took the time to explain how NEAR accounts, contracts, and keys work.
Shortly after, another awesome developer and member of the NEAR team, Mike Purvis also did up an excellent overview of NEAR accounts/keys. Highly recommend you take a few minutes and watch it as well.
Having watched both of these a couple times, I finally decided that the only way to fully understand what's going on is to try and teach it myself by putting into practice what they're talking about.
So, this is my deep dive into NEAR accounts, contracts, and keys. My end-state for writing this multi-part tutorial (and hopefully yours for reading it), is to completely understand how accounts, contracts and keys work together opening up cool possibilities for projects.
Part 1: NEAR Accounts
Starting with what the NEAR Protocol Specification says, we learn that NEAR has an account names system where every account has an account ID (which we can think of as a username). We learn they can be created explicitly and implicitly.
Remember that NEAR has several running networks...
When we create accounts, they get created on one of the NEAR networks - not all of them. As I write this, four exist: MainNet, TestNet, BetaNet, and LocalNet. While developing we tend to use the NEAR Testnet and that's the one we're going to connect to and create accounts on in this tutorial. Switching between networks on your machine is done with a command like this from a command prompt (putting the name of the network you want in place of testnet).
>> export NODE_ENV='testnet'
If you're using near-cli, it will default to Testnet if you forget to set it, but it's good practice to know where you are. You can always check if the NODE_ENV is set from VS Code bash terminal with:
>> echo $NODE_ENV
Explicit Account Creation
We explicitly create accounts at different levels. They are either top level accounts (TLAs) or sub-accounts belonging to the TLA created at increasing levels of depth below it.
Right now you can only create TLAs that are greater than 32 characters in length. (e.g. thisisareallylongtoplevelaccountname).
What about TLAs that are less than 32 characters in length?
They need to be created by the registrar account and that isn't deployed yet. It will be deployed by the NEAR Foundation at some point in the future. As shorter TLAs have value for branding (much like domain names), there will eventually be an auction where you will be able to bid on short TLAs (less than 32 characters in length). So, watch for that blog announcement if you want one.
We explicitly create second-level accounts using:
- NEAR wallet - via a simple web interface. Visit the TestNet Near Wallet to create a TestNet account (in my case aaron.testnet). This is currently the only way to create that first sub-level account which you'll typically want to do if you want to deploy contracts to sub-accounts beneath it. For example, we created vitalpointai.testnet and now deploy our contracts in development to third-level sub-accounts like dao.vitalpointai.testnet, paralog.vitalpointai.testnet, dao1.vitalpointai.testnet, and so on.
- With a second-level account created (aaron.testnet), we can now use NEAR-CLI - from the command line, and run a command in the following format to create third-level sub-accounts that are owned by our second-level account (aaron.testnet)
near create-account <yourcontractname> --masterAccount <login> --initialBalance <initialbalance>
How many levels of sub-accounts can one create?
The total length of an account name must be <= 64 characters. Thus, you can create as many sub-accounts and go down as many levels as you want until you reach that limit while also considering the current limits imposed on top level accounts. For example, using a .testnet TLA, 8 chars are used, leaving 52 to name sub-accounts with. Longest/deepest name we could get to based on that would be:
Keep in mind that each sub-account creation requires a transfer of NEAR from it's parent account - so depth will also be relative to how much NEAR is in the TLA that it can use to create the sub-accounts at each level below it.
>> export NODE_ENV='testnet'
>> near create-account firstaccount.aaron.testnet --masterAccount aaron.testnet --initialBalance 50
- Note that initialBalance is optional. If not there, it will default to transferring 100 NEAR from the masterAccount to the new account. On the flipside, you can delete the account and it's balance will be transferred back to its owner.
Implicit Account Creation
We can create accounts implicitly by generating a KeyPair, using its public key to reserve an account ID, and then transferring it some tokens. We create an account ID in the manner shown in the diagram above. Once we send some NEAR to that account ID (a minimum amount is required) it gets created and acts like a regular account until it's deleted.
The account ID is similar to what you'd find using Ethereum/Bitcoin. When we generate the KeyPair, the public key ends up mapping to the account ID and the corresponding private (secret) key allows you to sign transactions on behalf of that account ID once it's created on chain.
How we create implicit accounts matters as we can create them with or without seed phrases. If you generate an implicit account without a seed phrase - you should keep in mind that you will not be able to recover the account/import it into a wallet. If you create it with a seed phrase, you will be able to import it into/use it from a wallet.
Why would we want to create implicit accounts?
Here are a couple use case scenarios.
The Centralized Exchange Use Case
- In this scenario a centralized exchange lets users sign up and login to their platform. They need a way for users to deposit to an account they can then use to trade on the platform.
- The exchange generates an implicit account and associates it with a user's exchange account. That means the exchange controls the keypair (both public/private keys) of the implicit account.
- The exchange gives the user the account ID so they can make a deposit and start trading on the exchange. When the user wants to withdraw funds, they must submit a request to the exchange. The exchange processes the request (hopefully) and sends the desired amount from the user's implicit account balance to their desired recipient address/account.
- Using near-cli, that process looks like this:
First, we generate an example-key then use near repl to create an account ID from the key's public key:
Then we assign the 64 character key to an environment variable to make it easier to work with. Using that we can take a look at the key that was generated on our machine:
At this point, the account doesn't actually exist on chain. To create it on chain, we need to transfer an amount of NEAR to it as we do below by sending 1 NEAR from vitalpointai.testnet. Once that's done, the account exists on chain and we can use it like any other account (as long as we have access to the keypair). We use the near keys command to look at the keys associated with the account ID. Notice that it creates one full access key with nonce of 0.
This method of implicit account creation means you can only control the account from wherever you have the keypair. You will not be able to import it into NEAR wallet or any other wallet.
Let's Make the Account Recoverable
We can alter the above workflow slightly to make the implicit account recoverable by creating it with a seed phrase. We get the 12 word seed phrase from any BIP 39 mnemonic generator.
What is a BIP 39 Mnemonic phrase?
Bitcoin Improvement Proposal (BIP) 39 details implementation of a mnemonic phrase, mnemonic recovery phrase or bitcoin seed - all of which refer to a list of words that have all the info needed to recover a crypto currency wallet. Yes, we're dealing with NEAR ,not Bitcoin, but this is something that has been borrowed and is used across chains.
The software of a BIP 39 compliant wallet uses a list of 2048 words where every word is assigned a number. The 12 word phrase then gets converted to a number which is used as a seed that generates all pairs of keys for that wallet. That means the total number of possible combinations is 2048 to the 12th power, or 2 to the 132nd power - thus we refer to the phrase as having 132 bits of safety.
Usually, we let a generator provide us with a random mnemonic phrase. We could put one together on our own, but humans are typically not good at randomness and if we want something secure, it's best to use a phrase generated for us.
Like we did before, we need to transfer some NEAR to the account ID before it will exist on chain.
Unlike before, we actually can import this account ID into NEAR wallet (or other wallets) as there is now a seed phrase associated with it. Using the NEAR wallet add account workflow, we end up with the account imported like so:
This time, as you can see under the Full Access Keys heading above, there are two full access keys associated with the account. Every time you recover an account a new full access key will be added to it. You can also use the near keys command for near-cli to get the key info for the given account ID
Returning to our centralized exchange use case scenario, the exchange could simply create implicit accounts but if they ever lose the keys, there is no way of recovering the accounts or the crypto stored in them. That means some very unhappy people.
It would probably be a good idea for the exchange to implicit accounts using one or several BIP 39 mnemonic phrases, storing them offline in a safe place in event something catastrophic happens to their centralized setup. At least they'll be able to recover the accounts and regain access to their user's funds.
The Near Drop Use Case
- In this scenario an app wants to onboard a new user. The new user doesn't have a NEAR account.
- The app generates an implicit account ID which acts like a temporary account, attaches a deposit amount to it and bundles it into a near drop link (can be done with this tool for TestNet or MainNet or use this repo to help build your own). The app sends this link to its prospective user.
- The user receives and clicks the link which takes them to NEAR wallet where the wallet identifies that it is a near drop and directs the user to a flow that enables them to create a named account ID, choose an account recovery method, and claim the attached deposit.
- The implicit account is then deleted and the user has been effectively onboarded as a user with an account for the app.
Viewing Account Information
NEAR Explorer is your window to a real-time view of what's going on on the various NEAR networks. It is NEAR's version of Ethereum's Etherscan and will be a valuable tool as you begin to develop or use the NEAR blockchain.
When you get there, ensure you're looking at the right network (TESTNET) by selecting it from the drop down top right of the page. Now, type the account name you created above in the search box.
You'll be taken to the summary page for that account where it lists its current balance, storage used, transactions, when it was created and so on.
If there were transactions, they'd be listed and you'd be able to click on them to get more info about it.
We can get similar information (less transactions) using NEAR-CLI's near state command.
The default amount allocated to a TestNet account is currently 500 NEAR. However, when you look at the amount line from the near-cli output or the total balance from the NEAR explorer - it is less than 500 NEAR. What's going on?
For starters, the amount you see in the near-cli output is yocto NEAR. The amounts in the explorer have been formatted as NEAR. If you hover over the balance in the explorer view you'll see a popup with the full yocto NEAR amount matching the near-cli.
The NEAR token can be subdivided to 24 decimal places. In the metric system, SI prefixes were standardized for use in the International System of Units (SI) by the International Bureau of Weights and Measures (BIPM). Yocto is the unit prefix for 10^-24.
Everything done on a blockchain requires gas to pay for the compute and storage resources used. NEAR's gas fees are super low and predictable in contrast to a chain like Ethereum making it much more suitable for many high transaction applications.
Using HTTPie from the command line, we can query a TestNet RPC endpoint to see what the gas price was in the block where our account was created. The gas price typically remains constant and is fixed per block, but may change from block to block. If blocks become more than half full then gas price increases. A max gas price limit is being considered.
We can see that the price of gas when the account was created (block 23305918) was 1 nano NEAR (1 billionth of a NEAR, 1x10^9 or 1000000000 yocto). This gas price is used to calculate the gas fees associated with the various computations required to create the account. Here's a breakdown of what you see in the NEAR Explorer when a TestNet account is created.
Let's now revisit a couple of the other fields provided in the Near-Cli output and compare a non-contract account with a contract account:
This shows a couple of the formatting utils in action. Others can be found in the near-api-js API. In fact, everything we've done in this tutorial could have been accomplished in code using near-api-js and near-sdk-as (AssemblyScript) or near-sdk-rs (Rust).
In the first part of this multi-part tutorial we focused on NEAR Accounts. We learned:
- NEAR's account system is unique in the crypto world offering human readable names instead of long hex numbers;
- NEAR accounts can be created explicitly or implicitly and we can create them using tools like NEAR wallet or near-cli;
- NEAR accounts can be owned by other accounts thus creating a hierarchical relationship beginning with a top level account and moving deeper to second, third, fourth and so on levels of accounts;
- About a couple use cases for implicit accounts; and
- How to query the chain or use NEAR Explorer to get information about accounts to determine things like whether it has a contract deployed to it, fees associated with creating it, balance, and so on.
Next up in Part 2 - we'll explore account keys in more detail as they are also a very unique feature that NEAR provides opening the door to many interesting use cases. See you then.