Skip to content

Latest commit

 

History

History
385 lines (260 loc) · 18.4 KB

File metadata and controls

385 lines (260 loc) · 18.4 KB

Get Started

This tutorial is written for people who prefer to learn by doing. You might find this tutorial and the GitHub wiki complementary to each other.

Introduction

During this tutorial, we will build a small distributed App (dApp). The techniques you’ll learn in this guide are fundamental to building any dApp on Radix, and mastering it will give you a better understanding of Radix distributed ledger.

This guide is divided into several sections:

  • Basic Setup will give you a starting point to follow the tutorial.
  • Overview will teach you the fundamentals of Radix's architecture.
  • Getting some Radix tokens will show you how to build your first basic dApp.
  • Beyond the basics will give you additional examples to get a deeper insight into the strengths of Radix JS library.

About our example dApp

Our example dApp for this guide will basically get some free test money from Radix, and once it has enough money, our dApp will send some to a different address.
With our small dApp you'll learn how to interact with accounts, send transactions across the network and handle test tokens in an easy way.

Don't worry if you're new to Radix's concepts, as we will review the basic building blocks along the way.

Basic setup

Our next step is to set you up so that you can start building your first dApp with Radix.

Prepare your environment

Before we can begin, make sure you have a recent version of Node.js installed in your system. We'll also need a minimalistic Node.js boilerplate project so we can properly build and run our dApp. If you're experienced building your own Node.js applications, feel free to skip our next step and continue with the library installation.

Setting up a simple Node.js project

To prepare the environment, let's now set up a minimalistic Node.js project, by cloning an open source Webpack ES6 boilerplate:

git clone https://github.com/jluccisano/webpack-es6-boilerplate.git

Once we have cloned the boilerplate project, we can go ahead and install the required libraries for it:

cd webpack-es6-boilerplate/
npm install

As an optional step, you can start the server using npm start and open http://localhost:9000 on your browser to see if everything was set up correctly.

Installation

You can install the radixdlt library in your Node.js project using your preferred package manager:

Npm

npm install radixdlt --save

Yarn

yarn add radixdlt

{% hint style="info" %} Note: the radixdlt library provides full TypeScript support {% endhint %}

Recommendations

For this guide, we will assume that you have some familiarity with JavaScript, but you should be able to follow along even if you’re coming from a different programming language.

{% hint style="success" %} If you need to review JavaScript, we recommend reading this guide. {% endhint %}

We’ll also assume that you’re familiar with programming concepts like functions, objects, arrays, and classes. Additionally, having an understanding of Reactive programming, RxJS and observable patterns is suggested for a better insight.

{% hint style="success" %} If you need a quick review on Reactive programming, we recommend reading our blog post. {% endhint %}

Overview

Now that you’re set up, let’s dig a bit on the concepts that make Radix a unique distributed ledger technology, so we can share a common language.

Universe

A Universe represents the Radix network. It maintains connections to Nodes, and you can ask it to give you a connection to a node that serves a specific Shard.

{% hint style="info" %} Because Radix is built to be sharded from the ground up, it is not enough to have a single connection to the network - depending on what addresses you’re trying to work with, you might need a number of connections. {% endhint %}

Shards

A Shard is simply a segment of a Universe. A public Radix network (Universe) is segmented into a very large shard space (currently 2^64 shards). The shard number of an address is deterministically calculated, so it's trivial for anyone to correctly calculate the shard a public key lives on.

Nodes

A Node provides general computing and networking resources to the network. Nodes are responsible for validating events and transactions, relaying messages, resolving conflicts and executing scripts on the network. They also maintain a subset of the shard space, and get fees in proportion to their work.

Atoms

An Atom is the fundamental unit of storage on Radix's distributed ledger. Its structure defines one or more actions which update the ledger's state as an atomic transaction, that is, all-or-nothing.

Account

An Account represents all the data stored for a user on the ledger. This includes tokens, but also arbitrary data, as well as more advanced types of transactions in the future such as multi-sig and Scrypto smart contracts.

Address

An Address lives in a Shard and is the start and end point for any Atom in the Radix Universe. It's also a reference to an Account and allows a user to receive tokens and/or data from other users. A Radix address is generated from a public key and a Universe checksum.

{% hint style="info" %} Keep in mind, the defined Universe affects the generated Address. {% endhint %}

Account Systems

When an Account is connected to the network, it will take any incoming Atoms and pass them through the account systems. The default systems are:

  • Transfer System, which keeps a list of transactions involving this account as well as the account balance for all the different tokens in the account
  • Radix Messaging System, which manages the different Radix messaging chats this account is involved in
  • Data System used for custom data stored on the ledger

{% hint style="info" %} You can create your own custom Account Systems if you want access to the raw Atoms. {% endhint %}

Identity

An Identity represents a private key which can sign Atoms and read encrypted data. This private key can be stored in the application, or in the future, it might live elsewhere such as the users wallet application or hardware wallet.

{% hint style="info" %} The only type of Identity currently available is the Simple Identity, and it has a private key stored in memory. {% endhint %}

Transaction Builder

The Transaction Builder handles creating and submitting to the network any kind of Atoms that the Radix ledger can accept.
Right now this means token transfer atoms, data payload atoms and Radix messaging atoms (which are just a special case of the data payload atoms). In the future the atom model will be a lot more powerful.

Faucet Service

The Faucet service is a simple development service running on the Radix network that sends free test tokens back to any account that sends a message to it.

{% hint style="info" %} In the ALPHANET Universe, the Faucet service address is 9ey8A461d9hLUVXh7CgbYhfmqFzjzSBKHvPC8SMjccRDbkTs2aM {% endhint %}

Getting some Radix test tokens

Now that we have done a brief overview of the concepts behind Radix and we share a common language, we are ready to begin building our example dApp and get some Radix test tokens along the way.

Initializing the Universe

The first step, before we can interact with the ledger, is to choose which Universe we want to connect to.
We will use the ALPHANET universe configuration since it's our main testing environment, and the other development universes are used for testing unstable features.

Now, to initialize the universe we have to import the radixUniverse singleton from the library, and call the bootstrap function with the ALPHANET universe configuration:

import {radixUniverse, RadixUniverse} from 'radixdlt'radixUniverse.bootstrap(RadixUniverse.ALPHANET)

Creating our own Identity

As we want to interact with the ledger and be able to sign and decrypt atoms, we'll need to have our own Identity. To create a new random identity, we use the RadixIdentityManager:

const identityManager = new RadixIdentityManager()

Now we create a new random identity using the Identity Manager's generateSimpleIdentity() method:

const myIdentity = identityManager.generateSimpleIdentity()

With it, we can easily get our own Account using the account reference:

const myAccount = myIdentity.accountconsole.log('My account address: ', myAccount.getAddress())

{% hint style="info" %} Each Identity automatically comes with a corresponding Account. {% endhint %}

Opening the connection

Now that we have our account, the next step is connect it to the network. We do it by calling the openNodeConnection() method:

myAccount.openNodeConnection()

This call opens a connection to a Node from the ALPHANET universe which serves the shard where our account lives on, and asks the node for all the atoms in the address. It will also maintain a connection to the network until we destroy the account.

{% hint style="success" %} Tip: if a connection to a node dies, a new one will be found automatically. {% endhint %}

Getting the Faucet's account

To get the Faucet's account, we resolve the address using the fromAddress(...) method:

const faucetAddress = '9ey8A461d9hLUVXh7CgbYhfmqFzjzSBKHvPC8SMjccRDbkTs2aM'const faucetAccount = RadixAccount.fromAddress(faucetAddress, true)

Regarding the second boolean parameter, we set it to true, so the method doesn't create the default Account systems along the way.

{% hint style="success" %} For accounts that won't be connected to the network, since you won't need any accounting system, set the parameter to true. {% endhint %}

{% hint style="warning" %} Note: the library will throw an error if you accidentally try to use an address from a different Universe. {% endhint %}

Sending a message to the Faucet

Now that we have the Faucet's account and our own account connected to the network, we are ready to send a message and request some free tokens to the Faucet service.
We send the message using RadixTransactionBuilder's createRadixMessageAtom(...) method, and signing the result Atom with our Identity:

const message = 'Dear Faucet, may I please have some money? (◕ᴥ◕)'RadixTransactionBuilder
  .createRadixMessageAtom(myAccount, faucetAccount, message)
  .signAndSubmit(myIdentity)

Subscribing to balance updates

After we send the message, we have to subscribe to the Balance subject from the Transfer system to know when we receive the free test tokens sent by the Faucet service:

myAccount.transferSystem.balanceSubject.subscribe(balance => {
  // there's a balance update
  console.log(balance);
  // ...
})

{% hint style="info" %} The balance includes the type of token, and the amount of tokens in subunits. {% endhint %}

Handling tokens in Radix

As the balance can have different types of tokens, let's see now how we handle tokens in Radix using the RadixTokenManager.
Since we are working with the free test tokens, first we get the specific RadixToken by calling the getTokenbyISO(...) method from RadixTokenManager:

const radixToken = radixTokenManager.getTokenByISO('TEST')

We also noted that the balance is stored as token subunits (integer values), but we want to work with the balance as a regular floating point number, so we convert it using the toTokenUnits(...) method from RadixToken:

// Convert balance from subunits to decimal point value
const floatingPointBalance = radixToken.toTokenUnits(balance[radixToken.id.toString()])

{% hint style="info" %} Note: we convert token subunits to floating point on-demand to avoid inaccurate floating point calculations. {% endhint %}

Sending Radix tokens

Our last step is to send some of the free test tokens that we've got from the Faucet, to another address on the network. To do it, first we get the account from the destination address, just as we did before for the Faucet service:

// Put your friends' address here
const toAddress = '9i9hgAyBQuKvkw7Tg5FEbML59gDmtiwbJwAjBgq5mAU4iaA1ykM'
const toAccount = RadixAccount.fromAddress(toAddress, true)

We now have the destination account and our own account connected to the network, and we are ready to send a few test tokens to our friend's account.
We send the tokens using RadixTransactionBuilder's createTransferAtom(...) method, and signing the result Atom with our Identity:

// Send 5 tokens to the address
RadixTransactionBuilder
  .createTransferAtom(myAccount, toAccount, radixToken, 5)
  .signAndSubmit(myIdentity)

The complete dApp

At this point, we have all the basic building blocks for our simple "Get Radix test tokens" dApp. Now, to have a real complete and functional dApp, we need to put the pieces together:

import {radixUniverse, RadixUniverse} from 'radixdlt'
import {RadixIdentityManager, RadixAccount} from 'radixdlt'
import {RadixTransactionBuilder, radixTokenManager} from 'radixdlt'radixUniverse.bootstrap(RadixUniverse.ALPHANET)const identityManager = new RadixIdentityManager()
const myIdentity = identityManager.generateSimpleIdentity()
const myAccount = myIdentity.accountmyAccount.openNodeConnection()const faucetAddress = '9ey8A461d9hLUVXh7CgbYhfmqFzjzSBKHvPC8SMjccRDbkTs2aM'
const faucetAccount = RadixAccount.fromAddress(faucetAddress, true)
const message = 'Dear Faucet, may I please have some money? (◕ᴥ◕)'RadixTransactionBuilder
  .createRadixMessageAtom(myAccount, faucetAccount, message)
  .signAndSubmit(myIdentity)
  
  
const radixToken = radixTokenManager.getTokenByISO('TEST')  
myAccount.transferSystem.balanceSubject.subscribe(balance => {
  // Convert balance from subunits to decimal point value
  const floatingPointBalance = radixToken.toTokenUnits(balance[radixToken.id.toString()])
  // do we have at least 5 tokens?
  if (floatingPointBalance > 5) {
  
    // Put your friends' address here
    const toAddress = '9i9hgAyBQuKvkw7Tg5FEbML59gDmtiwbJwAjBgq5mAU4iaA1ykM'
    const toAccount = RadixAccount.fromAddress(toAddress, true)
    
    // Send 5 tokens to the address
    RadixTransactionBuilder
      .createTransferAtom(myAccount, toAccount, radixToken, 5)
      .signAndSubmit(myIdentity)
  }
})

Finally, to see this code running, we have to include it in our Node.js project.
If you're using the minimalistic boilerplate project that we set up previously, you only have to copy the dApp code shown above to the ./src/index.js file. You can also add the following line at the end of the file to get your Radix address in the web browser window:

document.getElementById('root').innerHTML = 'My address: '+ myAccount.getAddress();

To run the dApp, use npm start, and point your browser to http://127.0.0.1:9000. You should see your address on the main window, and if you open the developer console you will see the messages and atoms flowing through the network:

Beyond the basics

As we reach the end of our dApp example, we want to share some extra code snippets for those who want to go beyond the basics and showcase a few additional things that you can do with our library.

Example applications

Code examples

Join the Radix Community