The ultimate Solana step-by-step guide (including programs, dapps and Rust from scratch)
Published: 2022-03-28 01:39:25

**Welcome to the most complete open guide for people that want to dive
deep into Solana.**

**Whether you're an Ethereum developer, a blockchain developer, a web
developer or just a curious person, this is the #1 guide to become a
Solana developer. With extremely detailed steps so there's no room for
confusion along the way.**

![](https://cdn-images-1.medium.com/max/800/1*0rYfggygD5NOz57DFZ_2Hg.gif)

By the end of this complete guide you'll have accomplished **a working
dapp** that can be deployed to the blockchain and interact with the real
Solana blockchain for extremely low fees and fast confirmation times.

**Getting into Solana development can be extremely profitable** since
there's already a huge market of investors, users, defi enthusiasts, NFT
maniacs, cryptocurrency trades... A massive network of people that will
pay big money for the right products.

And **it's not nearly as saturated as in Ethereum** since many tools and
products haven't been developed yet in Solana for a good reason:
learning Solana and Rust is far more difficult but rewarding, plus it's
a new blockchain that continues to grow tremendously fast!

**I'm telling you, you'll find Rust hard at first but you'll love it by
the end of this article!**

You'll learn a ton of cool things including:

  - **Writing Solana Rust programs from scratch (no experience
    required)**
  - **Testing Solana applications with the Anchor framework**
  - **Developing a frontend for your dapp step-by-step**
  - **Connecting all the popular Solana wallets to your dapp**
  - **Deploying your dapp so it's permanently online**

**I like doing things hands-on, I believe it's the best way to learn.**
That's why in this guide you'll work through a dapp from an idea to its
complete deployment including all the blockchain coding and frontend
development as you learn along the way.

**We're gonna build a dapp that allows users to write a collective
article.** Imagine an open blockchain book where anybody can come in and
leave their little contribution to a grand story. **It could end up a
cool book or a total disaster.** In any case I'm excited to see how it
turns out!

Technically speaking, each wallet will be able to write 5 words to a
collective public article that lives permanently on the blockchain.
Kinda like a fun and open experimental game.

**It's a simple dapp and has a few functions which makes it ideal for
people to start getting into Solana development.**

If you're already familiar with the Solana Anchor setup already skip
directly to the section: **4. Coding the Rust program** to see how
to start coding this dapp. Otherwise read from the beginning.

If you feel this guide helped you in any way, be sure to join my email
list for updated on things I'm building in crypto and NFTs here:
<http://eepurl.com/dDQ2yX> and subscribe to me here!

Each chapter contains a short bullet list of the things you'll learn to
get you hyped up and excited for the new knowledge you're about to
acquire.

Here's what you're gonna learn:

1.  **Installing Rust, Solana, Yarn and Anchor**
2.  **Setting up the project from scratch**
3.  **Understanding the Anchor framework setup**
4.  **Coding the Rust program**
5.  **Creating the article update function**
6.  **Testing the Solana program**
7.  **Creating the decentralized application frontend**
8.  **Setting up the Solana wallets connection**

Let's do this! The updated code is available in my github as always
public and open to everybody. If you use it just give me credit so
people know who created it. The code is here:
<https://github.com/merlox/solana-world-article>

### 1. Installing Rust, Solana, Yarn and Anchor

Start by installing all the dependencies. We're gonna use Anchor which
is a framework that will make our lives easier for developing Solana
Rust programs.

In this section you'll learn:

  - How to install rust, solana, yarn and anchor
  - The commands required to verify the successful installation
  - Explanations for the different command tools installed

First, install Rust. Rust is the programming language used for Solana
programs, also known as Smart Contracts on Ethereum. You'll need to
install it first and foremost. To install Rust do:

```sh
curl -- proto '=https' -- tlsv1.2 -sSf <https://sh.rustup.rs> | sh
```

If you're in windows, install Git Bash from here:
<https://git-scm.com/downloads> which is a terminal that allows you to
run more unique commands not commonly available on windows, and then run
the previous Rust installation command on the Git Bash terminal.

Then run the following to add all the Rust executables to your PATH:

```sh
export PATH="$HOME/.cargo/bin:$PATH"
```

Make sure the installation was successful by running:

```sh
rustup --version  
rustc --version  
cargo --version
```

> Rustup is the upgrade utility that allows you to keep rust updated.
> You won't use it much.

> Rustc is the compiler. It's awesome because it allows you to take your
> program written in rust and make it executable on all operative
> systems. You won't use it for Solana programs but it's excellent if
> you're building any other app outside of it. Including desktop apps
> for all major systems.

> Cargo is the utility that allows us to install and manage
> dependencies. Think of it as npm for Rust.

Next, you can continue by installing Solana itself with this command:

```sh
sh -c "$(curl -sSfL https://release.solana.com/v1.9.8/install)"
```

Remember to keep an eye on this link
<https://docs.solana.com/cli/install-solana-cli-tools> to see the latest
version since they are constantly updating it.

After a successful installation run:

```sh
solana --version
```

To confirm that it has been added.

Now you'll have to install node.js with yarn which is required to work
with Anchor programs. Go to <https://nodejs.org/> and install the LTS
version.

![](https://cdn-images-1.medium.com/max/800/1*-1sKolo98NgtMZZusL0fsQ.png)

Once the installation is completed confirm the successful installation
like this:

```sh
node --version  
npm --version
```

Then install yarn, which is an improved version of npm with this
command:

```sh
npm i -g yarn
```

Finally install Anchor. Anchor is a protocol that allows us to build
programs on solana much faster and easier than without it. Think of it
as hardhat or truffle from Ethereum. An essential tool for any Solana
developer.

To install Anchor run:

```sh
cargo install --git https://github.com/project-serum/anchor
anchor-cli --locked
```

As you can see we're using Cargo which we installed earlier, it's very
simple just do cargo install and the git repository you wish to receive.

Confirm the installation with:

```sh
anchor --version
```

That should be it for the installation of all the dependencies. Let's
move on by setting up the project so we can create the program!

### 2. Setting up the project from scratch

Solana is configured to work on the mainnet network by default. This
means every transaction has a real SOL coin cost as the transaction fee.
You don't want to do that when developing applications. There's a better
way.

In this section you'll learn:

  - How to configure the solana cli utility to use devnet
  - Useful commands for solana
  - How to init a project with anchor framework

Use the devnet or testnet networks to develop your program and see how
they perform before deploying them to the main network where they will
be available to everyone.

So start by setting up solana to work with the devnet network like this:

```sh
solana config set --url devnet
```

Then generate your wallet which will be required to run and deploy your
programs with:

```sh
solana-keygen new --force
```

You'll see be asked to input a password to lock your wallet for
additional protection. Then you'll see your mnemonic which is a
combination of 12 words used to generate infinite addresses for your
wallet:

![Generating a new solana wallet with solana-keygen
new](https://cdn-images-1.medium.com/max/800/1*yG1q5c7o5I4BEOjmt9S8dQ.png)

You can then check your address with:

```sh
solana address
```

Give yourself some test Solana coins with the airdrop command:

```sh
solana airdrop 2
```

You can check your balance anytime with:

```sh
solana balance
```

Now that you have solana configured to work with the devnet network and
have a new wallet ready, let's setup an Anchor project which will create
all the folders and boring configuration for us. Go to your Desktop and
run this command:

```sh
anchor init solana-global-article  
cd solana-global-article
```

### 3. Understanding the Anchor framework setup

Let's take a look at what Anchor has done for you. Open the project with
your preferred code editor.

In this section you'll learn:

  - How to understand the code that anchor has created for you
  - The main files to pay attention to
  - Resources for deeper understanding of the anchor setup

You only have to pay attention to 2 files to begin coding.

The first and most important file is the `lib.rs` it's the main one that
will be loaded in the program:

```rs
use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
pub mod solana_global_article {
    use super::*;
    pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize {}
```

Anchor programs are pretty simple, you import the framework, then you
indicate where the `#program` contains the main logic and specify the
`#[derive(Accounts)]` which is where the data will be stored and where
you can access accounts.

The first line `use anchor_lang::prelude::*;` is just importing Anchor
so you can use all the goodness it provides for your program.

The `declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");` line
indicates the id of your program, the equivalent of the address for your
to-be-deployed smart contract in Ethereum. This is necessary for Anchor.

Then you specify the structs which are elements that contain the data
for your project with `#[derive(Accounts)]` . In Rust Solana programs
you separate the data and the functionality. Inside the `#program` block
you modify and access data but you don't store it there, all the data is
stored in `structs`.

Don't worry if it doesn't make much sense yet, you'll see what I mean
with the functionality / data separation soon enough.

The second file you have to understand is `Cargo.toml` which is the
equivalent to `package.json` if you're a javascript developer:

```rs
[package]
  name = "solana-global-article"
  version = "0.1.0"
  description = "Created with Anchor"
  edition = "2018"

[lib]
  crate-type = ["cdylib", "lib"]
  name = "solana_global_article"

[features]
  no-entrypoint = []
  no-idl = []
  no-log-ix-name = []
  cpi = ["no-entrypoint"]
  default = []

[dependencies]
  anchor-lang = "0.20.1"
```

As you can see you define the project data such the name, description
and then the dependencies at the bottom. You'll be adding things there
with `cargo install`.

I **highly** recommend you check this official anchor resource to see a
minimal example of the anchor configuration:
<https://project-serum.github.io/anchor/tutorials/tutorial-0.html#generating-a-client>

Continue ahead with the most interesting section where you'll begin to
use one of the coolest languages ever, Rust!

### 4. Coding the Rust program

Now the fun part, let's code the Rust program!

In this section you'll learn:

  - How to create a working Solana program according to your
    specification
  - The different attributes anchor gives you to make your life easier
  - How to understand Rust variables and syntax

If you remember we wanted to build a simple decentralized application
that allows users to write a shared article with anyone that uses
Solana. Kinda like an open book. Where people add their little knowledge
and fun elements.

The first step before coding is defining what we want our program to do
in a simple list:

  - Solana users will be able to connect their wallets and write 3 words
    on the global article
  - Up to 3 words per wallet but people can write less, so if someone
    just wants to add 1 word or 2 to the open book, they can do so
  - Words will be separated by spaces and we'll remove any empty space
    between them in Rust
  - Each word will have a maximum of 15 characters to keep it clean

> Every great project always starts with a clear vision of what the
> founder wants to build, it will save time and define a clear end goal

Great! Now open the global article project with your code editor and
navigate to `Programs > src > lib.rs` and open that file.

> Remember that `lib.rs` is the starter and main file for our solana
> program.

Let's start by creating the data structures where we'll store our
content. Add the `Article` struct:

```rs
#[account]
pub struct Article {
  pub content: String,
}
```

Here's the breakdown for you to fully understand what we just did:

  - As you can see we use the `pub` keyword which indicates this is a
    public `struct` which makes it accessible for other functions and
    structs. Without it you'll get an error saying `can't leak private
    type` .
  - Next we named our struct `Article` simply because this will be the
    article where we'll store our data. You can name it `Book` or
    something similar if you'd like.
  - Then we create the `content` property which is a `String` that will
    contain our information.

> Important: "Accounts" in Solana programs are like "files" in your
> computer. Their purpose is to store data. So when we say "account" in
> Solana, we mean a place to store your data. Accounts also have
> metadata that indicate the owner of that file and more.

Continue by creating the `Initialize` struct which is the one used to
setup the initial data and configurations. This is required because
unlike solidity, variables must be set initially:

```rs
#[derive(Accounts)]  
pub struct Initialize<'info> {  
  #[account(  
      init,  
      payer = person_that_pays,  
      space = 8 // account discriminator  
      + 32 // pubkey  
      + 10000 // make the message max 10k bytes long  
  )]  
  pub article: Account<'info, Article>,  
  #[account(mut)]  
  pub person_that_pays: Signer<'info>,  
  pub system_program: Program<'info, System>,  
}
```

Let's go line by line to understand what's going on. Try to copy the
code first and then read along:

  - `#[derive(Accounts)]` According to the official documentation derive
    accounts means: Implements an `Accounts` deserializer on the given
    struct. Meaning it allows this struct to process user addresses and
    accounts. You can see the official description here:
    <https://docs.rs/anchor-derive-accounts/0.18.2/anchor_derive_accounts/derive.Accounts.html>
  - Then we create a public struct like before but this time it is
    called `Initialize` and it has an `'info` lifetime. Lifetimes are a
    Rust thing that allow you to tell him to use a specific data from
    somewhere else. It's a way to pass variables. Don't worry if it's
    confusing you'll get used to it over time.
  - Next we initialize an `#[account(init, payer = person_that_pays,
    space = 8 + 32 + 10000]` . What we're doing here is telling the
    solana program to initialize an account where the data will be
    stored, then we define who's gonna pay for that transaction and the
    space we need for that data.
  - `pub article: Account<'info, Article>` : Here we are telling solana
    to store the article in the new data account we've created for it to
    be retrieved later.
  - `#[account(mut)]` `pub person_that_pays: Signer<'info>` : We
    defining the person that will pay to create the data account, which
    is a `Signer` type. It's the equivalent of setting up an owner in
    solidity, while `Signer` is the address type.
  - `pub system_program: Program<'info, System>,` : The `system_program`
    is a required element to create your solana data. Must be included
    in the initializer.

Now go to the `#program` section and create the main function to start
and setup the program like this:

```rs
#[program]  
pub mod solana_global_article {  
use super::*;  
pub fn initialize(ctx: Context) -> ProgramResult {  
  // Get the article  
  let article_account = &mut ctx.accounts.article;  
  // Initialize the variables (this is required)  
  article_account.content = ("").to_string();
  Ok(())  
  }  
}
```

The `initialize` function is receiving a `Context` with the `Initialize`
struct we've created before. Solana programs don't store state variables
in the same place like Ethereum smart contracts do, instead they
separate the data storage and the functionality.

That's why we always have to pass a `Context` into every solana program
function to receive the data we want to manipulate, since it can't
access data on its own.

What we're doing in this function is select the article struct we've
defined previously:

```rs
let article_account = &mut ctx.accounts.article;
```

And setup the content of that article struct to an empty string:

```rs
article_account.content = ("").to_string();
```

Finally we're returning the function with the `Ok(())` result. So what
we did is we went to this struct:

```rs
pub struct Article {
  pub content: String,
}
```

And initialized the content to an empty string that can be accessed
later. Variables need to be initialized to a starter value always.

Let's recap what we've done so far:

```rs
use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
pub mod solana_global_article {
  use super::*;
  pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {
    // Get the article
    let article_account = &mut ctx.accounts.article;
    // Initialize the variables (this is required)
    article_account.content = ("").to_string();

    Ok(())
  }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
  #[account(
    init,
    payer = person_that_pays,
    space = 8 // account discriminator
    + 32 // pubkey
    + 10000 // make the message max 10k bytes long
  )]
  pub article: Account<'info, Article>,
  #[account(mut)]
  pub person_that_pays: Signer<'info>,
  pub system_program: Program<'info, System>,
}

#[account]
pub struct Article {
    pub content: String,
}
```

You should have that code just like that. Now it's the perfect time to
run a `anchor build` in your terminal. The build command will tell you
whether your code is great or if it has any errors. It's very important
to do it often to catch issues early.

Continue reading to develop a complex Rust function in the next section.

### 5. Creating the article update function

So far we've setup a simple program that doesn't do much. It's time to
create the function that allows people to write the article data.

In this section you'll learn:

  - How to create a struct that updates data in the Solana blockchain
  - A simple explanation on Rust variable types
  - How to use the `.spli()` function and iterate over it

The first step when creating a function that updates blockchain data, is
to create a struct with the variables you want to have updated like so:

```rs
#[derive(Accounts)]  
pub struct WriteIntoArticle<'info> {  
  // Here goes the info that you want to modify like this  
  #[account(mut)]  
  pub article: Account<'info, Article>,  
}
```

You start by adding the `#[derive(Accounts)]` modifier which is required
to make this work.

Then you setup the name of it. In this case I chose `WriteIntoArticle` .
After that you include the struct you want to modify, in this case it's
gonna be the `Article` struct so that's why I saved it with the
`article` variable name.

As you can see we've added the `#[account(mut)]` attribute. This is so
we can modify the article data since `mut` in Rust indicates a mutable
variable that can be updated.

To put it simply, in Rust you declare a **constant** like this:

```rs
let my_variable = 10; // This value can't be changed
```

And a variable with the `mut` modifier:

```rs
let mut my_variable = 10;  
my_variable = 5; // It works
```

When we create a mutable account with an attribute like this
`#[account(mut)]` what we're doing is telling Solana that this data will
be modified in the future. In this case, our `article` variable will be
updated with new data.

The mutable account attribute is required otherwise we won't be able to
modify that data.

Now we can write the function that will use our newly-created struct:

```rs
pub fn write_into_article(  
  ctx: Context,  
  three_words: String, // If more, after 3 they will be removed  
) -> ProgramResult {  
  // To update the article string  
  let article = &mut ctx.accounts.article;  
  let split_iterator = three_words.trim().split(" ");``` ```
  Ok(())  
}
```

First we define the `write_into_article` function which receives the
context `WriteIntoArticle` and a String variable called `three_words`
which is the data our users will send to write into the global article.

Then we read the `article` data by accessting the `&mut
ctx.accounts.article` context variable.

Since we want people to send a string made of 3 words, we gotta split it
into separate units so we can check that each word is valid, meaning:

  - Each word is made of less than 15 characters
  - To remove all the extra empty spaces in between words
  - To verify if the user actually sent 3 words or more

The `trim()` function will remove empty spaces between words while
`split(" ")` will separate words by spaces. Note that `split()` returns
an iterator. We can't access the data without iterating over it first or
`collect()` ing it.

Now let's iterate over those words to check it the user sent more words
than permitted since that's not allowed because we want multiple people
to contribute to this global article project. Add the following below
the `split_iterator` variable:

```rs
let split_iterator = three_words.trim().split(" ");  
let mut final_words = Vec::new();  
let mut counter_added = 0;  
for s in split_iterator {  
  if s.trim().is_empty() {  
    continue;  
  }  
  if s.trim().len() >= 15 {  
    return Err(Errors::WordTooLong.into());  
  }  
  final_words.push(s);  
  counter_added += 1;  
  if counter_added >= 3 {  
    break;  
  }  
}  

Ok(())
```

There' s a lot going on, so let's break it down for your understanding:

  - `let mut final_words = Vec::new()` : The final_words variable will
    contain a list of the 3 words. Vectors are arrays of variable size
    in Rust. You can push items to them. They have to be initialized
    with `Vec::new()` . In this case we're making it `mut` able because
    we want to add items to it later.
  - `let mut counter_added = 0;` : This is a counter that will keep
    track of how many words we're adding to the list to stop at 3 and
    not add more than necessary.
  - `for s in split_iterator {}` : Remember that `split_iterator` is an
    iterator which means we gotta loop through it to access each item.
    We are doing that with a simple `for in` loop which stores each item
    into the `s` variable.
  - `if s.trim().is_empty() { continue; }` : Here we're checking if the
    word is empty or not and if so, skip it. This is because when we
    split by spaces we may find that we have words separated by several
    spaces. The split function then recognizes empty spaces as words, so
    we get rid of those empty words with a simple `if` statement.
  - `if s.trim().len() >= 15 { return Err(Errors::WordTooLong.into());
    }` : Here we're checking if the word inside the variable `s` has 15
    characters or more, in which case we return an error. In this case
    I've called the error `WordTooLong` . You'll see later on how we
    create and define the error messages. The `Err` function is from
    `anchor` and it allows us to send and error and stop execution.
  - `final_words.push(s); counter_added += 1;` : Here we're simply
    adding the word to the `final_words` vector after checking it is
    valid to our conditions and increasing the counter.
  - `if counter_added >= 3 { break; }`: If the counter is 3 or more,
    stop the loop. This is so if people send more than 3 words, we cut
    off and remove the remaining ones.

As you can see we're doing quite a few things in that little code. It's
good that you get familiar with Rust syntax. You'll love it in no time.

Now let's continue with the final part of that function which looks like
the following:

```rs
// Join the 3 words after removing spaces
let mut joined_words = final_words.join(" ");
// Add a space at the end with this
joined_words.push_str(" ");
// Article content gets immediately updated
article.content.push_str(&joined_words);
```

First we join the words we've extracted and cleaned up with the `join("
")` method which combines words into one string and separates them by a
space.

Then we add a space at the end of those 3 words. The way you do that is,
you take the `joined_words` string and push another string to it with
`.push_str(" ")` which is the way you concatenate strings in Rust.

Finally you update your article global variable with the same push
method to concatenate words `article.content.push_str(&joined_words);`
note that we don't do `article.content =
article.content.push_str(&joined_words);` that's because the `push_str`
method updates the original string.

Now we can go ahead and define the errors section which is pretty simple
as you'll see. Right at the end of the file below all the structs and
programs write this:

```rs
#[error]  
pub enum Errors {  
  #[msg("Each word must be less than 15 characters")]  
  WordTooLong,  
}
```

The `#[error]` attribute indicates this `enum` is the one containing the
error definitions.

Then we simply add the keywords we want, in my case it's just
`WordTooLong` for the error name and a message on top with the `msg`
attribute. The message in quotes will be displayed when the error is
called.

That should be it for the Solana program code! You did it!

You can see the updated and complete code for the program in my github
here:
<https://github.com/merlox/solana-world-article/blob/master/programs/solana-global-article/src/lib.rs>

### 6. Testing the Solana program

In Solana rust programs you **always** test the code since as far as I
know, there are no tools you can use to interact with the programs
directly like in ethereum with the verified contracts in etherscan and
remix. You don't have that here.

In this section you'll learn:

  - How to write Solana tests using the anchor protocol
  - How to execute Rust programs from anchor
  - How to get data from the blockchain

So let's get testing! It's pretty simple as you'll see, just long lines
of code. This is the initial setup:

```js
import * as anchor from '@project-serum/anchor'  
import { Program } from '@project-serum/anchor'
import { GlobalArticleTutorial } from '../target/types/global_article_tutorial'

describe('global-article-tutorial', () => {
  // Configure the client to use the local cluster.  
  anchor.setProvider(anchor.Provider.env())
  const program = anchor.workspace.GlobalArticleTutorial as Program
  
  it('Is initialized!', async () => {  
    // Add your test here.  
    const tx = await program.rpc.initialize({}) 
    console.log("Your transaction signature", tx)
  })
})
```

Anchor imports all the required libraries for you at the top and then
creates a simple test to see if the intialization would work. There's an
issue, this first test will fail.

Simply because the `initialize` function is not receiving the right
parameters. Modify the first test initialization function `const tx =
await program.rpc.initialize({})` with this object for it to work:

```js
it('Is initialized!', async () => {  
  const deployerKeypair = anchor.web3.Keypair.generate()  
  const personThatPays = program.provider.wallet
  
  // Add your test here  
  await program.rpc.initialize({  
    accounts: {
      article: deployerKeypair.publicKey,  
      personThatPays: personThatPays.publicKey,  
      systemProgram: anchor.web3.SystemProgram.programId,  
    },  
    signers: [deployerKeypair],  
  })
})
```

What we're doing there is creating a new `Keypair` which is a sample
account used for the test. Then we get the wallet that will pay for the
initialization.

As you can see inside `initialize` we've added an `accounts` object
which, if you remember from before, it's where the data is stored and we
simply add the initial data.

The required data are the variables from the `Initialize` struct.
However note that the variables use camelCase notation, when in our rust
program, we've defined those variables with snake_case notation.

For instance, `personThatPays` in the test is `person_that_pays` in the
`Initialize` struct. Keep that in mind.

Now run the test with `anchor test` and it should be successful. You can
use the devnet network or use the local solana network which lives in
your computer exclusively for testing purposes. Go ahead and follow
these steps:

1.  Run `solana config set --url localhost` , this will change the
    network you use to localhost instead of devnet.
2.  Then do run the command `solana-test-validator` and stop it after a
    few seconds. If you keep it running your tests won't run, since it
    needs to work in the background.
3.  Open your `Anchor.toml` file and update the `[programs.devnet]`
    block to `[programs.localnet]`
4.  Then in that same file update `cluster = "devnet"` to `cluster =
    "localnet"` .

If it was successful you'll see this message:

```js
1 passing (243ms)
```

Let's now write the second test which will include the functionality to
write into the global article. We'll do a one word test first. Start by
creating the test structure:

```js
it('Should write an article with 1 word successfully', async () => {})
```

Then copy the code to from the previous test to initialize the program.
When testing we don't care if we're repeating code or adding unnecessary
lines since it's code used exclusively for development. It won't be used
by users:

```js
it('Should write an article with 1 word successfully', async () => {
  const deployerKeypair = anchor.web3.Keypair.generate()  
  const personThatPays = program.provider.wallet

  await program.rpc.initialize({  
    accounts: {  
      article: deployerKeypair.publicKey,  
      personThatPays: personThatPays.publicKey,  
      systemProgram: anchor.web3.SystemProgram.programId,  
    },  
    signers: [deployerKeypair],  
  })
})
```

Now let's add some additional functionality to write an article to the
blockchain. Go ahead and add the following function right below the
initialize method:

```js
await program.rpc.writeIntoArticle('hey', {  
  accounts: {  
    article: deployerKeypair.publicKey,  
  },  
  signers: [],  
})
```

As you can see we're executing the `writeIntoArticle` function from the
program. The first parameter `'hey'` is the word we're gonna add to the
blockchain, while the second parameter is a javascript object containing
the `accounts` with the `article` data.

Remember that `accounts` in Solana are pieces of storage kinda like
files stored in the blockchain. They don't represent a username and
password. Although they have some metadata inside them to determine who
created that data and so on.

In this case we're simply updating the `article` variable and we're
sending it the signer which is the `deployedKeypair.publicKey` to let
the program know, who is sending this data.

At this point, you may be wondering: "how do I read the information
stored in the blockchain?". Good question. And the way you do that is
with the `.fetch()` or `.all()` methods. The `.all()` method allows you
to retrieve all the elements in a variable, in case you have an array or
vector in your rust program.

Here's how we check the article data we just sent to the blockchain:

```js
const articleData = await program.account.article.fetch(deployerKeypair.publicKey)  
expect(articleData.content).to.equal('hey ')
```

We do `await` the method `fetch()` from the actual `article` object in
our `program` while sending it the `publicKey` . This way we're getting
the actual data stored in the blockchain.

Then we execute the final part of the test which is verifying that the
information we just sent is what we expected with the `expect()`
function.

Note the empty space right after the word `'hey '` . It is intentional
to add a separator for the next words people add in the future.

If you run the test with `anchor test` you'll notice that there's an
error, that's because we're using `expect()` which is a testing function
from the `'chai'` package. In order for the test to work, you must
import expect like this at the top of the file:

```js
import { expect } from 'chai'
```

You don't have to install that dependency because `anchor` has already
done that for you.

Here's how the test looks in its entirity:

```js
import { expect } from 'chai' // Keep this at the beginning of the file along with the other imports

it('Should write an article with 1 word successfully', async () => {
  const deployerKeypair = anchor.web3.Keypair.generate()
  const personThatPays = program.provider.wallet

  // Add your test here
  await program.rpc.initialize({
    accounts: {
      article: deployerKeypair.publicKey,
      personThatPays: personThatPays.publicKey,
      systemProgram: anchor.web3.SystemProgram.programId,
    },
    signers: [deployerKeypair],
  })
  
  await program.rpc.writeIntoArticle('hey', {
    accounts: {
      article: deployerKeypair.publicKey,
    },
    signers: [],
  })

  const articleData = await program.account.article.fetch(deployerKeypair.publicKey)
  expect(articleData.content).to.equal('hey ') // Note the space at the end, added by the program
})
```

Run the tests again with `anchor test` , you should see a message like
the following if they are successful:

```js
✔ Is initialized! (494ms)  
✔ Should write an article with 1 word successfully (942ms)
2 passing (1s)
```

It's time for the final test. The one where we check if we can add 3
words several times. We won't write a test for when a user sends more
than 3 words to the article since I don't want to bother you with all
this testing.

But if the code is right, when a user send more than 3 words to the
global article, they should only write 3 words while the rest are
removed.

Here's how the third test looks like:

```js
it("should write 3 words two times", async () => {
  const deployerKeypair = anchor.web3.Keypair.generate()
  const personThatPays = program.provider.wallet

  // Add your test here
  await program.rpc.initialize({
    accounts: {
      article: deployerKeypair.publicKey,
      personThatPays: personThatPays.publicKey,
      systemProgram: anchor.web3.SystemProgram.programId,
    },
    signers: [deployerKeypair],
  })
  
  await program.rpc.writeIntoArticle('hey whats up', {
    accounts: {
      article: deployerKeypair.publicKey,
    },
    signers: [],
  })

  await program.rpc.writeIntoArticle('this is my', {
    accounts: {
      article: deployerKeypair.publicKey,
    },
    signers: [],
  })

  const articleData = await program.account.article.fetch(deployerKeypair.publicKey)
  console.log('article data', articleData)
  expect(articleData.content).to.equal('hey whats up this is my ') // Note the space at the end, added by the program
})
```

As you can see, we've copied the previous tests initially to keep that
same setup while updating the `writeIntoArticle` function with the text
`'hey whats up'` and repeating the same function with the text `'this is
my'` .

You can write anything really but that's to see if we are able to
concatenate several writes to the blockchain for the purposes of having
a global article made by several people.

We then do a `fetch()` and check if the article content is what we want,
with an empty space at the end. Note the `console.log()` I've added,
that's to see how the data received looks like. I encourage you to do
the same and get familiar with the responses the solana blockchain gives
you.

Write the test by hand, don't copy paste it because you don't develop
the muscle memory necessary to truly understand how these things work
until you use your hands.

Now run it with `anchor test` for a successful result:

```js
✔ Is initialized! (181ms)  
✔ Should write an article with 1 word successfully (958ms)  
article data { content: 'hey whats up this is my ' }  
✔ should write 3 words two times (1448ms)
3 passing (3s)
```

As an exercise, try to write a new test that tries to `writeIntoArticle`
more than 4 words and see what happens.

That should be it! The program is tested and ready to go! Let us now
create the frontend which is what people will use to interact with the
program from their computers. It's gonna be awesome, let's go.

### 7. Creating the decentralized application frontend

It's time to put it all together into a great looking dapp for people to
play around and interact with your program. Let's get to it.

In this section you'll learn:

  - How to create a React frontend for your dapp
  - How to setup webpack with the different plugins
  - How to use Material UI and stylus for the design

The frontend will live in a separate folder inside the same project you
started before. That's because there are many files and they need their
own config. Anchor created the `app/` folder specifically for that. For
the frontend.

I usually start by creating the webpack configuration myself with the
initial files. But I found a better way.
[Createapp.dev](https://createapp.dev) is the app (they didn't pay me to
say this, I just like it) I use now to generate the initial setup.

You simply go to the website, choose webpack and setup the files by
clicking on the options you want. If you want my configuration, just
copy the following gif. Make sure to have Material UI selected in the UI
library section since we'll use it later:

![A gif showing you the process to generate the starter frontend files
with createapp.dev, an awesome utility. This is a mac screen recording
converted to gif with ffmpeg
btw](https://cdn-images-1.medium.com/max/800/1*MvmvEfzOzIYEEJsTIWjFJw.gif)

Once you download the folder you'll see the files according to the
chosen configuration, in my case they are the following:

```js
package.json  
README.md  
src/  
-- App.js  
-- index.js  
-- styles.styl  
webpack.config.js
```

What's great is that we have access to the build webpack configuration
and we can adapt it to however we want. I chose to use stylus since it's
great for css configurations.

I put all those files inside the `app/` folder of the project we had
earlier. Navigate to that folder from the terminal and execute:

```sh
yarn install
```

Create a file called:

```sh
.gitignore
```

And inside that file simply indicate which folders and files to ignore
when uploading your project in github. You can copy the configuration
from the same site you used to create the config:

![](https://cdn-images-1.medium.com/max/800/1*7_2sLy4xxye0wT5OFsCGWg.png)

Then, inside your `package.json` in the `scripts` section add a new
script used to start our dapp so it looks like the following:

```js
"scripts": {  
  "clean": "rm dist/bundle.js",  
  "build-dev": "webpack --mode development",  
  "build-prod": "webpack --mode production",  
  "watch": "webpack --mode production -w",  
  "serve": "npx http-server docs",  
  "start": "npm-run-all --parallel watch serve"
},
```

You'll need to install `http-server` locally with:

```sh
yarn add http-server
```

And `npm-run-all` globally for the scripts to work:

```sh
npm i -g npm-run-all
```

For some reason the createapp.dev app doesn't create a `.babelrc` file.
You gotta do it yourself. At the root of your `app/` folder create a
`.babelrc` file and copy the contents from the page.

![](https://cdn-images-1.medium.com/max/800/1*YgTw0pRd5nGbzZ44l4A-2A.png)

You may see a different configuration based on which parameters you
chose.

Then update your `webpack.config.js` to output the compiled files to
`docs/` since we'll use that to host our dapp for free with github pages
as you'll see later on:

```js
output: {
  path: path.resolve(__dirname, 'docs'),  
  filename: 'bundle.js'  
},
```

Now let's go ahead and create a simple frontend design, it will look
like the following:

![The solana open global book
design](https://cdn-images-1.medium.com/max/800/1*0rYfggygD5NOz57DFZ_2Hg.gif)

A simple input where we input the words we want to add to the book and
submit. Users can connect with the button at the top right. Then they
choose the wallet they want to use and they approve transactions.

The first thing is to create the design. Open `App.js` you'll see
something like this:

```js
import React from 'react'  
import Button from '@material-ui/core/Button'

class App extends React.Component {  
  render() {  
    const { name } = this.props  
    return (
      <> 
        Hello {name} this is a material UI button
      </>
    )  
  }  
}

export default App
```

Let's change that to a functional React component:

```js
import React from 'react'  
import Button from '@material-ui/core/Button'

const App = () => {  
  return (  
    <>  
      Hello this is a material UI button
    </>  
  )
}

export default App
```

You can see how it looks anytime with `yarn start` in fact I recommend
you to keep it open while you develop.

If you get this error:

```js
ERROR in unable to locate
'/Users/merunas/Desktop/solana-global-article/app-tutorial/src/index.html'
glob
```

You have to simply update the `webpack.config.js` file by removing the
`CopyPlugin` for now.

The Material UI library added by that web app is outdated. So go to your
`App.js` and update the imports:

```js
import Button from '@material-ui/core/Button'
```

To:

```js
import { Paper, Skeleton, TextField, Button} from '@mui/material'
```

Then install these ones:

```sh
yarn add @mui/material @emotion/react @emotion/styled
```

Update your `App` component to the following for the initial structure
while using the Material UI components we've imported earlier:

```js
const App = () => {
  return (
    <>
    <header className='header'>
      <div className="title-container">
      <h1 className="main-title">Open Global Book</h1>
      <h4 className="main-subtitle">By Merunas</h4>
      </div>
    </header>
    <Paper elevation={20} className='content-box'>
      <Skeleton variant='text' />
      <Skeleton variant='text' />
      <Skeleton variant='text' />
    </Paper>
    <div className="three-words-input-container">
      <TextField
      id='outlined-basic'
      label='Write to the open book (5 words max)'
      variant='outlined'
      className='words-input'
      />
      <Button variant="contained" className="submit-button">Submit</Button>
    </div>
    </>
  )
}
```

We added a header with a title and subtitle. Then a `Paper` section with
3 `Skeleton` to create a loading text component that feels like it's
retrieving data from the blockchain. We'll create that later on.

Finally we have a section with the inputs using the `TextField` and
button to submit. It will look like this:

![](https://cdn-images-1.medium.com/max/800/1*zhdaXv61GVWipxQ7FquLCw.png)

Not great. But that's what the CSS classes we added are for. Go to your
`styles.styl` file and paste this code:

```css
*
  font-family: 'roboto'

.header
  display: flex
  align-items: center

.title-container
  width: 100%

.main-title
  margin-bottom: 0

.main-subtitle
  margin-top: 0

.wallet-connect
  width: 200px

.content-box
  max-width: 800px
  margin: auto
  padding: 20px
  margin-top: 10px
  margin-bottom: 30px

.solana-image
  width: 70px
  margin-top: 7px

.three-words-input-container
  max-width: 800px
  margin: auto
  display: flex
  justify-content: space-around
  align-items: center

.words-input
  width: 410px

.helper-description
  max-width: 800px
  margin: auto
  margin-top: 100px
  color: grey
  font-size: 10pt
  
@media (max-width: 500px)
  .three-words-input-container
    flex-direction: column

    .submit-button
      margin-top: 20px

    .words-input
      width: 100%
```

Your dapp will look like this now:

![](https://cdn-images-1.medium.com/max/800/1*1L4TeRm8eac4FIy-MPvC4Q.png)

Notice how the font is not quite right. That's because we haven't added
the `Roboto` font Material Ui uses. To add the font, we'll update
`webpack.config.js` so that the `HtmlWebpackPlugin` uses a file we can
easily edit:

```js
new HtmlWebpackPlugin({
 title: 'Solana Global Book',
 template: './src/index.ejs',
 filename: 'index.html',
}),
```

Then create an `index.ejs` inside `src` . You may be wondering: "What is
.ejs?". EJS is a template node engine that we will use to update the
title of our dapp directly from webpack with a variable. It allows you
to add variables easily.

Here's how the `index.ejs` looks like:

```html
<!DOCTYPE html>
<html lang="en" dir="ltr">
 <head>
  <meta charset="utf-8" />
  <title><%= htmlWebpackPlugin.options.title %></title>
  <link
    rel="stylesheet"
    href="https://fonts.googleapis.com/css family=Roboto:300,400,500,700&display=swap"
  />
  <meta name="viewport" content="initial-scale=1, width=device-width" />
 </head>
 <body>
  <div id="app"></div>
 </body>
</html>
```

Notice how we're importing the roboto font and using the `title`
variable from webpack in between those `<%= %>` special tags. They come
from EJS.

Now the font is much better:

![](https://cdn-images-1.medium.com/max/800/1*K869K7ffOQTKJB6UGYj-LA.png)

The next step is to add the solana logo. Simply download it from here:
<https://raw.githubusercontent.com/merlox/solana-world-article/master/app/assets/solana.jpeg>

Create an `assets` folder inside `app/` and move the `solana.jpg` file
right there. Then modify `App.js` to include the logo:

```html
<header className='header'>
  <img src='assets/solana.jpeg' className='solana-image' />
  <div className="title-container">
    <h1 className="main-title">Open Global Book</h1>
    <h4 className="main-subtitle">By Merunas</h4>
  </div>
</header>
```

However that won't work just yet. We gotta tell webpack to move the
assets to the `docs/` folder where the combined files live. Update
`webpack.config.js` plugins to this:

```js
new CopyPlugin({
  patterns: [
    {
      from: 'assets',
      to: 'assets',
    },
  ],
}),
```

Now reload webpack by stopping the terminal and doing `yarn start`
again.

![](https://cdn-images-1.medium.com/max/800/1*2fEUtbihIwp9m11ZwD66mw.png)

You can see the logo properly positioned! That's because of the css
we've added earlier and the classes in `App.js` .

In the next section you'll learn how to connect Phantom and other Solana
wallets to work with the blockchain.

### 8. Setting up the Solana wallets connection

In this section you'll learn:

  - How to connect Phantom and many other wallets easily
  - How to configure the React components to work with Solana
  - How to use the different libraries designed by Anchor and Solana

To interact with the blockchain we need a way to let our dapp send and
receive information to your wallet. There are many ways to set it up.
But in this case we'll use the many libraries configured to work with
react and Phantom.

If you haven't done so yet, download <https://phantom.app/> for your
browser and create an account. It is the Metamask equivalent for Solana.
Works flawlessly.

Then create a file called `WalletContext.js` inside `src/` and import
all these libraries at the top:

```js
import React from 'react'
import {
 ConnectionProvider,
 WalletProvider,
} from '@solana/wallet-adapter-react'
import { WalletAdapterNetwork } from '@solana/wallet-adapter-base'
import {
 LedgerWalletAdapter,
 PhantomWalletAdapter,
 SlopeWalletAdapter,
 SolflareWalletAdapter,
 SolletExtensionWalletAdapter,
 SolletWalletAdapter,
 TorusWalletAdapter,
} from '@solana/wallet-adapter-wallets'
import {
 WalletModalProvider,
} from '@solana/wallet-adapter-react-ui'
import config from './../config'
require('@solana/wallet-adapter-react-ui/styles.css')
```

Note that I created a file named `config.js` which simply contains a
javascript object with some configuration that we'll use for several
files. So go ahead and create a file named `config.js` right outside the
`src/` folder with these contents:

```js
export default {
  solana_article_account: '',
  network: 'devnet',
  endpoint: 'https://api.devnet.solana.com',
}
```

The `solana_article_account` will be the address of the account that
holds the data for the article. As you know, **accounts hold data**.

Install the following dependencies with yarn:

```sh
yarn add @solana/wallet-adapter-react @solana/wallet-adapter-base @solana/wallet-adapter-wallets @solana wallet-adapter-react-ui
```

Then add the rest of the configuration for the wallet connection
context:

```js
export default ({ children }) => {
 const network = WalletAdapterNetwork.Devnet
 const wallets = [
  new PhantomWalletAdapter(),
  new SlopeWalletAdapter(),
  new SolflareWalletAdapter({ network }),
  new TorusWalletAdapter(),
  new LedgerWalletAdapter(),
  new SolletWalletAdapter({ network }),
  new SolletExtensionWalletAdapter({ network }),
 ]
return (
  <ConnectionProvider endpoint={config.endpoint}>
   <WalletProvider wallets={wallets} autoConnect>
    <WalletModalProvider>
     {children}
    </WalletModalProvider>
   </WalletProvider>
  </ConnectionProvider>
 )
}
```

There's a lot going on. It took me a while to set it up properly because
many tutorial online don't explain how this works so I'll be very
descriptive for you:

  - First we take the network that will be used for the wallet
    connections. This is only necessary for the Solflare, Sollet and
    SolletExtension wallets. For some reason the `WalletAdapterNetwork`
    doesn't have an option for `localhost` networks. But that's fine, we
    can work without it.
  - Then we create an array of wallets we are gonna use. Simply do a
    `new` for every wallet we've imported previously from the
    `@solana/wallet-adapter-wallets` library. You can just import
    `PhantomWalletAdapter` if you're not gonna use the others.
  - Then, in the return you gotta place those components in the order
    I've shown you. Notice the `{children}` variable. That one is
    necessary because our entire dapp will be placed there. The children
    variable is a function argument as you can see at the beginning
    `export default ({ children }) => {}` .

Our entire dapp will be inside that `children` variable. It is required
because all those wallet and connection providers will be passed down to
the main `App` where they will be used to interact with the program
we've created.

Just so you understand, in our App component we will add the following:

```html
<WalletContext>
  <App/>
</WalletContext>
```

Where `WalletContext` is the entire list of providers that we're
returning from the `WalletContext.js` file we created earlier. Meaning,
our app is a child of all those providers so we can access the wallet
connection in all of our components. Let me know if you got any more
questions regarding this point in the comments.

Now go back to the `App.js` file and import the file we've just created:

```js
import WalletContext from './WalletContext'
```

Right at the end of the file, use it to hold the App like so:

```js
export default () => {
 return (
  <WalletContext>
   <App/>
  </WalletContext>
 )
}
```

Then, in the App component add a wallet connect button in the header:

```html
<header className='header'>
  <img src='assets/solana.jpeg' className='solana-image' />
  <div className="title-container">
    <h1 className="main-title">Open Global Book</h1>
    <h4 className="main-subtitle">By Merunas</h4>
  </div>
  <div className="wallet-connect">
    <WalletMultiButton />
  </div>
</header>
```

That button comes from this library:

```js
import { WalletMultiButton } from '@solana/wallet-adapter-react-ui'
```

Now it's a good time to run `yarn start` and see how the app looks...
unfortunately you will find an error in the webpack build that says:

```js
BREAKING CHANGE: webpack < 5 used to include polyfills for
node.js core modules by default.  
This is no longer the case. Verify if you need this module and configure
a polyfill for it.
```

This had me searching for solutions for a good while. It basically
means, some of the libraries we've imported use specific `node.js`
utilities such as `fs` or `path` that are meant to be used for server
purposes. Webpack in versions 4 and older did include all those
libraries whenever necessary.

But now, webpack 5 doesn't include the required node libraries for your
imports to work.

In summary, you gotta go and tell webpack to not worry about those
imports. You can do that by adding the following to your webpack config:

```js
resolve: {
  fallback: {
    fs: false,
    tls: false,
    net: false,
    path: false,
    zlib: false,
    http: false,
    https: false,
    stream: false,
    crypto: false,
    process: false,
  },
},
```

Right at the same level of `output` and `entry` . That should fix all
the compilation errors and your app will load with no issues.

Some people suggest downgrading to webpack 4. In my opinion that's a
terrible idea. You shouldn't be forced to use older versions that may or
may not work. It is much better to fix those issues like I just did.

Start your app with `yarn start` and see how it looks. If you still get
errors, install and import this webpack plugin
<https://www.npmjs.com/package/node-polyfill-webpack-plugin>.

You'll now see the phantom solana button like so:

![](https://cdn-images-1.medium.com/max/800/1*pEGnFXPJmfLdjtJSMnx4ug.png)

You can click on it to connect your wallet, just be sure to be on the
same network you configured previously. Remember that in your
`config.js` you've added this:

```js
endpoint: 'https://api.devnet.solana.com',
```

So in your phantom wallet be sure to select the devnet network. However
I recommend you to deploy your program to localhost first and then
you'll be able test it faster. In which case you'll have to change your
phantom extension config to use localhost and update the `config.js`
file endpoint.

Anyway. Congrats! you've got a working wallet connection that not only
looks good, but works flawlessly. Your frontend is ready to start
interacting with the blockchain. Let's continue with the next section!

### 9. Connecting the Solana program with our created React frontend

In this last section, you'll learn:

  - How to take connect your program with your phantom wallet through
    your dapp
  - How to read the Solana blockchain data from your program
  - How to write data into the blockchain for the Article struct

Let' s start by setting up the state variables. Import `useState` from
react like so in your `App.js` file:

```js
import React, { useState } from 'react'
```

Then create these variables inside the `App` component:

```js
const [inputValue, setInputValue] = useState('')  
const [isLoading, setIsLoading] = useState(true)  
const [solanaArticle, setSolanaArticle] = useState('')
```

The `inputValue` variable will be used to hold the data users type into
the input component. The `isLoading` variable is gonna be used to verify
when the data has finished loading from the blockchain mainly to display
the loading lines from Material UI and replace them with actual data
once available.

Then the `solanaArticle` variable is going to hold the data stored in
the solana blockchain used to display that information for the book.

After doing that, we'll setup the variables required for the wallet
blockchain connection, you can place them right below the state
variables:

```js
const wallet = useAnchorWallet()  
const { connection } = useConnection()
```

You'll have to import those 2 elements from the `wallet-adapter-react`
library like so:

```js
import { useConnection, useAnchorWallet } from '@solana/wallet-adapter-react'
```

At this point your App component will look like this:

```js
import React, { useState } from 'react'
import { Paper, Skeleton, TextField, Button } from '@mui/material'
import WalletContext from './WalletContext'
import { WalletMultiButton } from '@solana/wallet-adapter-react-ui'
import { useConnection, useAnchorWallet } from '@solana/wallet-adapter-react'
const App = () => {
  const [inputValue, setInputValue] = useState('')
  const [isLoading, setIsLoading] = useState(true)
  const [solanaArticle, setSolanaArticle] = useState('')
  const wallet = useAnchorWallet()
  const { connection } = useConnection()
  return (
    // Omitted for brevity
  )
}
```

Before diving into the blockchain stuff, let's make sure our input HTML
element works by verifying the user is inputing 5 words while each word
being limited to 15 characters, separated by a space. To do that, find
your `TextField` component and include these fields:

```js
<TextField
  id='outlined-basic'
  label='Write to the open book (5 words max)'
  variant='outlined'
  className='words-input'
  value={inputValue}
  onChange={e => checkAndAddWords(e)}
/>
```

In React, the `value` attribute is required when updating the input data
programatically. As you can see, the `onChange` function is executing
the `checkAndAddWords(e)` we're about to create with the event received:

```js
const checkAndAddWords = e => {
  let words = e.target.value.split(' ')
  for (let i = 0; i < words.length; i++) {
   if (words[i].length > 15) {
    return
   }
  }
  if (words.length > 5) return
  setInputValue(words.join(' '))
}
```

There we're simply check that the words have 15 chars or less and we
stop the user from typing after adding 5 words.

Now let's get to the juicy part. We're gonna use the `initialize`
function from our program into the dapp so we can create and store data
into the blockchain. If you remember the Rust `initialize` function we
created does create an Account that stores the article data. Go ahead
and copy this code by hand:

```js
const initialize = async () => {
  const provider = new Provider(connection, wallet, {})
  const program = new Program(idl, programID, provider)
  const keypairOne = Keypair.generate()
  try {
    await program.rpc.initialize({
    accounts: {
      person_that_pays: provider.wallet.publicKey,
      article: keypairOne.publicKey,
      systemProgram: SystemProgram.programId,
    },
    signers: [keypairOne],
    })
    console.log('done', keypairOne.publicKey.toString())
  } catch (e) {
    console.log('#1', e)
    return alert(e)
  }
}
```

Here's the breakdown:

  - We create the `provider` which is the connection to the phantom
    wallet.
  - Then we setup the `program` to interact with it. As you can see we
    need an IDL, programID and provider. We'll get those in a moment.
  - Then we create a new account keypair. This is the account where the
    data of our program will be stored.
  - Next, we do a try catch to run the `initialize` function from the
    program methods. It receives `accounts` and `signers` . This is the
    same structure we have in our program.
  - Accounts holds the `person_that_pays` which is the account that pays
    the transaction fees and rent costs for 2 years to keep that data
    online.
  - The `article` variable is the account we've passed and is gonna be
    used for the `data` we're about to store. And the system program is
    just the Solana main program.
  - After we're done, we log the account generated since we'll need it
    in a moment to keep updating the same data later on.

Go ahead and import the required elements like so:

```js
import idl from './solana_global_article.json'
import { Program, Provider, web3 } from '@project-serum/anchor'
import { PublicKey } from '@solana/web3.js'
import config from './../config'
const programID = new PublicKey(idl.metadata.address)
const { SystemProgram, Keypair } = web3
```

The `solana_global_article.json` import you can get it from your
`target/deploy/.json` which was created when you did `anchor build` .
Simply copy that one to your `src/` folder.

Then install `yarn add @project-serum/anchor @solana/web3.js` which are
required for the dapp to work. After that, setup the programID and the
other `web3` dependencies.

Try to run it now with `yarn start` . If at this point you're getting a
weird error like `process not defined` in your chrome dev tools, you can
simply fix it by following these steps:

1.  Doo `yarn add node-polyfill-webpack-plugin`
2.  In your webpack config add this: `const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')`
3.  Then add it to the plugins section: `new NodePolyfillPlugin()`

Now it should work.

The `initialize` function should only be ran once by the creator of the
program. Although it can be ran as many times as you want to create new
`article` accounts used for storing data.

To execute it, simply add a button like this somewhere in your app:

```js
<Button onClick={initialize} color="secondary" variant="contained">initialize</Button>
```

You'll see the button and after clicking it a Phantom wallet transaction
popup will show up for you to confirm the initialization. Just make sure
you're in the same network as you configured in your `WalletContext.js`
file.

Then you'll see the console log message with the `Keypair.generate()`
result:

![](https://cdn-images-1.medium.com/max/800/1*CfpImGg4ITqO2O-Kvc8Uqg.png)

That's gonna be the address where the article data will be stored. Copy
it and paste it into your `config.js` file.

```js
solana_article_account: '6LUM5nyBDT7CKqiJPrEsweKzdQktFDiGTsaRq6iG96c4',
```

You can now remove or comment out the `initialize` button you've
created.

At this point we can just read the blockchain data with a function like
the following:

```js
const getAndSetArticle = async () => {
  const provider = new Provider(connection, wallet, {})
  const program = new Program(idl, programID, provider)
  const articleData = await program.account.article.fetch(config.solana_article_account)
  setSolanaArticle(articleData.content)
  setIsLoading(false)
}
```

Which simply initializes the program like before and gets the article
data froom the blockchain with the `fetch` method. Then it updates the
state variables to see that new information in the dapp.

Make sure to execute that function when the React component is setup and
ready using `useEffect` from React like so:

```js
useEffect(() => {
  if (wallet) {
   getAndSetArticle()
  }
}, [wallet])
```

Remember to import it at the top of your file:

```js
import React, { useState, useEffect } from 'react'
```

That way, once the component is ready to use, the function will be
executed and you'll see the article data.

Now update the `Skeleton` visual loaders with the information we receive
from the blockchain:

```js
{isLoading ? (
  <Paper elevation={20} className='content-box'>
   <Skeleton variant='text' />
   <Skeleton variant='text' />
   <Skeleton variant='text' />
  </Paper>
) : (
  <Paper elevation={20} className='content-box'>
   {solanaArticle}
  </Paper>
)}
```

Once the `isLoading` state is set to false, the app will show the
`solanaArticle` data to the user. Try it and see how it loads. The
skeleton will dissapear but you won't see any data because there's none
in the blockchain yet.

Let's change that. We're gonna create a function to upload words to our
global article. Here's how it looks like:

```js
const uploadWords = async () => {
  const provider = new Provider(connection, wallet, {})
  const program = new Program(idl, programID, provider)
  try {
    await program.rpc.writeIntoArticle(inputValue, {
      accounts: {
      article: config.solana_article_account,
      },
    })
  } catch (e) {
    console.log('#2', e)
    return alert(e)
  }
  getAndSetArticle()
}
```

Here's the breakdown:

  - First we setup the provider and program like we did before.
  - Then we do a try catch but this time we're executing the
    `writeIntoArticle` method which is exactly the function
    `write_into_article` in our Rust program.
  - Notice how we're passing as the first parameter the `inputValue`
    which is nothing more than what the user has typed in the input form
    we have setup.
  - Then we pass the article public key that we've generated before.
    That is nothing more but the address of the account that holds the
    `article` data.
  - At the end we update the data shown in the dapp by retrieving what's
    being stored in the blockchain with the `getAndSetArticle()`
    function.

What's left now, is to find the submit button and add a click event
listener that will call the `uploadWords` function we've just created:

```js
<Button
  variant='contained'
  className='submit-button'
  onClick={uploadWords}
>
  Submit
</Button>
```

Go ahead and try it out with `yarn start`! You'll see your final dapp
fully working, sending and receiving data from the Solana blockchain!
Isn't it awesome? For sure it is. Check it out and play around!

![](https://cdn-images-1.medium.com/max/800/1*yaH1p8rBnZPnsTutpx_5Ew.gif)

If you've liked it, be sure to join my new 3D interactive NFTs project [Nuclei One](https://nuclei.one)