DEV Community 👩‍💻👨‍💻

Cover image for The Complete Guide to Full Stack Solana Development with React, Anchor, Rust, and Phantom
Nader Dabit for Edge and Node

Posted on • Updated on

The Complete Guide to Full Stack Solana Development with React, Anchor, Rust, and Phantom

Building Full Stack dapps with React, Solana, Anchor, and Phantom wallet.

In The Complete Guide to Full Stack Ethereum Development I did a deep dive into how to build a full stack dapp on Ethereum, which can also be applied to other EVM compatible chains like Polygon, Avalanche, and Ethereum Layer 2's like Arbitrum.

In this guide, I want to dive into Solana to show you how to build a full stack dapp. I also want to introduce the the ecosystem and the developer tooling to you to hopefully help you get up and running building your own ideas and applications going forward.

The code for the project is located here

Solana developer overview

As someone who just started learning Solidity and its ecosystem about 6 months ago, I kind of assumed it couldn't be that much harder to get up and running with. I was wrong.

Parts of the developer tooling are really nice and polished (the Solana CLI and Anchor), while the rest of the ecosystem, and even the documentation for Anchor (which to be fair, is very new), leaves a decent amount to be desired.

That being said, once you get the hang of everything it quickly becomes much easier to understand how to start implementing your own ideas and begin experimenting.

One of the keys to finding answers is to be vigilant about searching across all of Google, Github, and especially the various Discord servers for Anchor and Solana. The developers in those channels have been extremely helpful, especially Armani Ferrante who created the Anchor framework. Get familiar with the search feature, you can often find answers to your questions in past discussions in Discord.

Project overview

The tooling we'll be using today includes:

Solana Tool Suite - This includes a really polished and well documented CLI for interacting with the Solana network.

Anchor Framework - Anchor is actually a life saver for me, and I'm almost certain I would not have been able to get over the hump of building anything without it. It is the Hardhat of Solana development and more, and I love it. It also offers a DSL on top of Rust so that you do not need a deep understanding of the language to get started, though I am still trying to learn Rust as it will probably be useful to build anything non-trivial, even with the DSL. A good free place to learn Rust is The Rust Book.

solana/web3.js - A Solana version of web3.js that seems to work pretty well, but the documentation was almost unusable for me

React - The client-side framework

I will leave off all of the in depth details around how Solana itself works, as other people can cover this better than me. Instead I'll try to just focus on building something and sharing the details that you need to be know to accomplish this, along with things I think are of utmost importance.

If you want to learn more about Solana and how it works, here are a few good pieces:

In this guide we'll focus mainly on project setup, testing, and front end client integration for building out a couple of types of applications, mainly focused on CRUD operations (without the delete of course), which I found to be somewhat undocumented (integration with client applications).

We'll also learn how to airdrop tokens to our own development accounts using the Solana CLI, and deploy our apps to both a local network as well as a live test network.

We won't be focusing on NFTs in this guide, but maybe I will focus on doing that in a future guide. For now, if you're interested in building an NFT marketplace on Solana, I recommend checking out Metaplex.

Prerequisites

This tutorial covers how to build a full stack app on Solana, but does not go into how to install all of the individual dependencies.

Instead, I will list the dependencies and link to the documentation for how to install them, as each project will be able to explain and document these things better than I ever could, as well as keep them up to date.

  1. Node.js - I recommend installing Node using either nvm or fnm

  2. Solana Tool Suite - You can see the installation instructions here. note - If you have any issues installing Solana on an M1 Mac, try building from source and check out this guide.

  3. Anchor (including the Mocha installation) - Anchor installation was pretty straight-forward for me. You can find the installation instructions here.

  4. Solana browser wallet - I recommend Phantom, which is what I have tested this app with.

Getting Started

Before we get started building, let's take a look at the Solana CLI.

Solana CLI

The main things we'll be doing with the Solana CLI will be configuring our network (between localhost and a developer testnet) as well as airdropping tokens into our wallets, pretty much everything else we'll be doing with the Anchor CLI.

For instance, we can check the current network (and other) configuration with this command:

solana config get

# output
Config File: /Users/user/.config/solana/cli/config.yml
RPC URL: https://api.devnet.solana.com
WebSocket URL: wss://api.devnet.solana.com/ (computed)
Keypair Path: /Users/user/.config/solana/id.json
Commitment: confirmed
Enter fullscreen mode Exit fullscreen mode

If you do not have a Keypair path, set one up by following the instructions here

We can change the network like so:

# set to localhost
solana config set --url localhost

# set to devnet
solana config set --url devnet
Enter fullscreen mode Exit fullscreen mode

This is important as you will need to be aware of which network you are using as you're building, testing, and deploying your programs. You also need to be sure your wallet is using the same network that your local environment is using when testing, something I'll cover.

We'll be starting by developing on a localhost network, then switching to the devnet network.

We can also use the CLI to see our current local wallet address:

solana address
Enter fullscreen mode Exit fullscreen mode

And then get the full details about an account:

solana account <address from above>
Enter fullscreen mode Exit fullscreen mode

Next let's airdrop some tokens. To do so, first switch to the local network, as this is where we will be working to start off with:

solana config set --url localhost
Enter fullscreen mode Exit fullscreen mode

Next, start the local network. This is going to be a local Solana node that we can deploy to for testing:

solana-test-validator
Enter fullscreen mode Exit fullscreen mode

Once the local network is running, you can airdrop tokens to your account. With the network running, open a separate window and run the following command:

solana airdrop 100
Enter fullscreen mode Exit fullscreen mode

You can the check the balance of your wallet:

solana balance

# or

solana balance <address>
Enter fullscreen mode Exit fullscreen mode

You should now have a balance 100 SOL in your wallet. With that, we can get started building.

Let's start building

To get started, initialize a new anchor project and change into the new directory:

anchor init mysolanaapp --javascript

cd mysolanaapp
Enter fullscreen mode Exit fullscreen mode

Be sure to use Anchor version 0.16.0 or later.

In this project, you'll see four main folders (in addition to the node_modules):

app - Where our frontend code will go

programs - This is where the Rust code lives for the Solana program

test - Where the JavaScript tests for the program live

migrations - A basic deploy script

Let's take a look at the program that was created for us.

Anchor uses, and enables us to write, an eDSL (embedded DSL) that abstracts away many of the more complex low level operations you'd typically need to do if you were using Solana & Rust without it, making it more approachable for me.

// programs/src/lib.rs
use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

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

#[derive(Accounts)]
pub struct Initialize {}
Enter fullscreen mode Exit fullscreen mode

This is probably the most basic program you can write. The only thing happening here is we are defining a function called initialize, which when invoked just exits the program successfully. There is no data manipulation at all.

The Initialize struct defines the context as being empty of any arguments. We'll learn more about the function context later.

To compile this program, we can run the Anchor build command:

anchor build
Enter fullscreen mode Exit fullscreen mode

Once a build is completed, you should see a new folder named target.

One of the artifacts created is an IDL located at target/idl/mysolanaapp.json.

IDLs are very similar to an ABI in Solidity (or a query definition in GraphQL), and we will be using them in a similar way in our JavaScript tests and frontends to communicate with our Solana program via RPC.

We can also test out our program. If you open tests/mysolanaapp.js, you will see that there is a test written in JavaScript that allows us to test out the program.

The test should look like this:

const anchor = require('@project-serum/anchor');

describe('mysolanaapp', () => {
  // Configure the client to use the local cluster.
  anchor.setProvider(anchor.Provider.env());

  it('Is initialized!', async () => {
    const program = anchor.workspace.Mysolanaapp;
    const tx = await program.rpc.initialize();
    console.log("Your transaction signature", tx);
  });
});
Enter fullscreen mode Exit fullscreen mode

There are a couple of things to learn from this test that are important and we'll be using in the future, both in our tests as well as in the front end JavaScript clients.

To call a Solana program using Anchor, we typically need two main things:

1. Provider - The Provider is an abstraction of a connection to the Solana network, typically consisting of a Connection, Wallet, and a preflight commitment.

In the test, the Anchor framework will create the provider for us based on the environment (anchor.Provider.env()), but on the client we will need to construct the Provider ourselves using the user's Solana wallet.

2. program - The program is an abstraction that combines the Provider, idl, and the programID (which is generated when the program is built) and allows us to call RPC methods against our program.

Again, like with the Provider, Anchor offers a convenient way to access the program, but when building out the front end we'll need to construct this provider ourselves.

Once we have these two things, we can start calling functions in our program. For example, in our program we have an initialize function. In our test, you'll see we can invoke that function directly using program.rpc.functionName:

const tx = await program.rpc.initialize();
Enter fullscreen mode Exit fullscreen mode

This is a very common pattern that you'll use a lot when working with Anchor, and once you get the hang of understanding how it works, makes it really easy to connect to and interact with a Solana program.

We can now test the program by running the test script:

anchor test
Enter fullscreen mode Exit fullscreen mode

Building Hello World

Now that we have our project setup, let's create something a little more interesting.

I know that, as a full stack developer, most of the time I'm wondering how to do CRUD types of operations, so that's what we'll look at next.

The first program we'll create will allow us to create a counter that increments every time we call it from a client application.

The first thing we need to do is open programs/mysolanaapp/src/lib.rs and update it with the following code:

use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
mod mysolanaapp {
    use super::*;

    pub fn create(ctx: Context<Create>) -> ProgramResult {
        let base_account = &mut ctx.accounts.base_account;
        base_account.count = 0;
        Ok(())
    }

    pub fn increment(ctx: Context<Increment>) -> ProgramResult {
        let base_account = &mut ctx.accounts.base_account;
        base_account.count += 1;
        Ok(())
    }
}

// Transaction instructions
#[derive(Accounts)]
pub struct Create<'info> {
    #[account(init, payer = user, space = 16 + 16)]
    pub base_account: Account<'info, BaseAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program <'info, System>,
}

// Transaction instructions
#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut)]
    pub base_account: Account<'info, BaseAccount>,
}

// An account that goes inside a transaction instruction
#[account]
pub struct BaseAccount {
    pub count: u64,
}
Enter fullscreen mode Exit fullscreen mode

In this program we have two functions - create and increment. These two functions are the RPC request handlers that we will be able to call from a client application to interact with the program.

The first parameter of an RPC handler is the Context struct, which describes the context that will be passed in when the function is called and how to handle it. In the case of Create, we are expecting three parameters: base_account, user, and system_program.

The #[account(...)] attributes define constraints and instructions that are related to the proceeding account where declared. If any of these constraints do not hold, then the instruction will never execute.

Any client calling this program with the proper base_account can call these RPC methods.

The way that Solana deals with data is much different than anything I've ever worked with. There is no persisted state within the program, everything is attached to what are known as accounts. An account essentially holds all of the state of a program. Because of this, all data is passed by reference from the outside.

There are also no read operations. This is because all you need to do to read the contents of a program is to request the account, from there you are able to view all of the program's state. To read more about how accounts work, check out this post.

To build the program:

anchor build
Enter fullscreen mode Exit fullscreen mode

Next, let's write a test that uses this counter program. To do so, open tests/mysolanaapp.js and update with the following code:

const assert = require("assert");
const anchor = require("@project-serum/anchor");
const { SystemProgram } = anchor.web3;

describe("mysolanaapp", () => {
  /* create and set a Provider */
  const provider = anchor.Provider.env();
  anchor.setProvider(provider);
  const program = anchor.workspace.Mysolanaapp;
  it("Creates a counter)", async () => {
    /* Call the create function via RPC */
    const baseAccount = anchor.web3.Keypair.generate();
    await program.rpc.create({
      accounts: {
        baseAccount: baseAccount.publicKey,
        user: provider.wallet.publicKey,
        systemProgram: SystemProgram.programId,
      },
      signers: [baseAccount],
    });

    /* Fetch the account and check the value of count */
    const account = await program.account.baseAccount.fetch(baseAccount.publicKey);
    console.log('Count 0: ', account.count.toString())
    assert.ok(account.count.toString() == 0);
    _baseAccount = baseAccount;

  });

  it("Increments the counter", async () => {
    const baseAccount = _baseAccount;

    await program.rpc.increment({
      accounts: {
        baseAccount: baseAccount.publicKey,
      },
    });

    const account = await program.account.baseAccount.fetch(baseAccount.publicKey);
    console.log('Count 1: ', account.count.toString())
    assert.ok(account.count.toString() == 1);
  });
});
Enter fullscreen mode Exit fullscreen mode

Before we continue to test and deploy the program, we want to get the dynamically generated Program ID that was generated by the build. We need this ID to use in the Rust program to replace the placeholder ID we set up when we created the project. To get this ID, we can run the following command:

solana address -k target/deploy/mysolanaapp-keypair.json
Enter fullscreen mode Exit fullscreen mode

We can now update the program IDs in lib.rs:

// mysolanaapp/src/lib.rs

declare_id!("your-program-id");
Enter fullscreen mode Exit fullscreen mode

And in Anchor.toml:

# Anchor.toml
[programs.localnet]
mysolanaapp = "your-program-id"
Enter fullscreen mode Exit fullscreen mode

Next, run the test:

anchor test
Enter fullscreen mode Exit fullscreen mode

Once the test passes, we can now deploy.

We can now deploy the program. Be sure that solana-test-validator is running:

anchor deploy
Enter fullscreen mode Exit fullscreen mode

You can also view the validator logging by opening a separate window and running solana logs

Now we're ready to build out the front end.

Building the React app

In the root of the Anchor project, create a new react app to overwrite the existing app directory:

npx create-react-app app
Enter fullscreen mode Exit fullscreen mode

Next, install the dependencies we'll need for Anchor and Solana Web3:

cd app

npm install @project-serum/anchor @solana/web3.js
Enter fullscreen mode Exit fullscreen mode

We'll also be using Solana Wallet Adapter to handle connecting the user's Solana wallet. Let's install those dependencies as well:

npm install @solana/wallet-adapter-react \
@solana/wallet-adapter-react-ui @solana/wallet-adapter-wallets \
@solana/wallet-adapter-base
Enter fullscreen mode Exit fullscreen mode

Next, in the src directory, create a new file named idl.json. Here, copy the IDL JSON that was created for you in the main project folder, located at target/idl/mysolanaapp.json.

It would be nice if we could copy this idl file automatically to our client application src folder, but as of now I have not found a way to do this natively. You can of course create your own script that does this if you'd like, or else you need to copy and paste over the IDL after every change to your main program.

If you want a script like this, you can do it in just a couple of lines of code:

// copyIdl.js
const fs = require('fs');
const idl = require('./target/idl/mysolanaapp.json');

fs.writeFileSync('./app/src/idl.json', JSON.stringify(idl));
Enter fullscreen mode Exit fullscreen mode

Next, open app/src/App.js and update it with the following:

import './App.css';
import { useState } from 'react';
import { Connection, PublicKey } from '@solana/web3.js';
import {
  Program, Provider, web3
} from '@project-serum/anchor';
import idl from './idl.json';

import { PhantomWalletAdapter } from '@solana/wallet-adapter-wallets';
import { useWallet, WalletProvider, ConnectionProvider } from '@solana/wallet-adapter-react';
import { WalletModalProvider, WalletMultiButton } from '@solana/wallet-adapter-react-ui';
require('@solana/wallet-adapter-react-ui/styles.css');

const wallets = [
  /* view list of available wallets at https://github.com/solana-labs/wallet-adapter#wallets */
  new PhantomWalletAdapter()
]

const { SystemProgram, Keypair } = web3;
/* create an account  */
const baseAccount = Keypair.generate();
const opts = {
  preflightCommitment: "processed"
}
const programID = new PublicKey(idl.metadata.address);

function App() {
  const [value, setValue] = useState(null);
  const wallet = useWallet();

  async function getProvider() {
    /* create the provider and return it to the caller */
    /* network set to local network for now */
    const network = "http://127.0.0.1:8899";
    const connection = new Connection(network, opts.preflightCommitment);

    const provider = new Provider(
      connection, wallet, opts.preflightCommitment,
    );
    return provider;
  }

  async function createCounter() {    
    const provider = await getProvider()
    /* create the program interface combining the idl, program ID, and provider */
    const program = new Program(idl, programID, provider);
    try {
      /* interact with the program via rpc */
      await program.rpc.create({
        accounts: {
          baseAccount: baseAccount.publicKey,
          user: provider.wallet.publicKey,
          systemProgram: SystemProgram.programId,
        },
        signers: [baseAccount]
      });

      const account = await program.account.baseAccount.fetch(baseAccount.publicKey);
      console.log('account: ', account);
      setValue(account.count.toString());
    } catch (err) {
      console.log("Transaction error: ", err);
    }
  }

  async function increment() {
    const provider = await getProvider();
    const program = new Program(idl, programID, provider);
    await program.rpc.increment({
      accounts: {
        baseAccount: baseAccount.publicKey
      }
    });

    const account = await program.account.baseAccount.fetch(baseAccount.publicKey);
    console.log('account: ', account);
    setValue(account.count.toString());
  }

  if (!wallet.connected) {
    /* If the user's wallet is not connected, display connect wallet button. */
    return (
      <div style={{ display: 'flex', justifyContent: 'center', marginTop:'100px' }}>
        <WalletMultiButton />
      </div>
    )
  } else {
    return (
      <div className="App">
        <div>
          {
            !value && (<button onClick={createCounter}>Create counter</button>)
          }
          {
            value && <button onClick={increment}>Increment counter</button>
          }

          {
            value && value >= Number(0) ? (
              <h2>{value}</h2>
            ) : (
              <h3>Please create the counter.</h3>
            )
          }
        </div>
      </div>
    );
  }
}

/* wallet configuration as specified here: https://github.com/solana-labs/wallet-adapter#setup */
const AppWithProvider = () => (
  <ConnectionProvider endpoint="http://127.0.0.1:8899">
    <WalletProvider wallets={wallets} autoConnect>
      <WalletModalProvider>
        <App />
      </WalletModalProvider>
    </WalletProvider>
  </ConnectionProvider>
)

export default AppWithProvider;
Enter fullscreen mode Exit fullscreen mode

Switching your wallet network

Before we can interact with a program on the localhost network, we must switch our Phantom wallet to the proper network.

To do so, open your Phantom wallet and click the settings button. Then scroll down to Change Network:

Updating network

Next, choose Localhost:

Choosing localhost

Now we need to airdrop tokens to this wallet. At the top of the wallet interface, click on your address to copy it to your clipboard.

Wallet address

Next, open your terminal and run this command (be sure solana-test-validator is running):

solana airdrop 10 <address>
Enter fullscreen mode Exit fullscreen mode

You should now have 10 tokens in your wallet. Now, we can run and test the app!

Change into the app directory and run the following command:

npm start
Enter fullscreen mode Exit fullscreen mode

You should be able to connect your wallet, create a counter, and increment it.

You'll notice that when you refresh, you lose the state of the program. This is because we are dynamically generating the base account when the program loads. If you wanted to read and interact with the program data across various clients, you would need to create and store the Keypair somewhere in your project. I've put together a gist of a naive approach of how this might look.

Hello World part 2

Let's create a variation of this program that, instead of dealing with a counter, allows us to create a message and keep track of all of the previously created messages.

To do so, let's update our Rust program to look like this:

/* programs/mysolanaapp/src/lib.rs */
use anchor_lang::prelude::*;

declare_id!("your-program-id");

#[program]
mod mysolanaapp {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>, data: String) -> ProgramResult {
        let base_account = &mut ctx.accounts.base_account;
        let copy = data.clone();
        base_account.data = data;
        base_account.data_list.push(copy);
        Ok(())
    }

    pub fn update(ctx: Context<Update>, data: String) -> ProgramResult {
        let base_account = &mut ctx.accounts.base_account;
        let copy = data.clone();
        base_account.data = data;
        base_account.data_list.push(copy);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 64 + 64)]
    pub base_account: Account<'info, BaseAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Update<'info> {
    #[account(mut)]
    pub base_account: Account<'info, BaseAccount>,
}

#[account]
pub struct BaseAccount {
    pub data: String,
    pub data_list: Vec<String>,
}
Enter fullscreen mode Exit fullscreen mode

In this program we have two main pieces of data we're keeping track of, a String named data and a Vector that holds a list of all data ever added to the program named data_list.

You'll notice that the memory allocation here is higher (128 + 128) than the previous program in order to account for the Vector. I don't know how many updates you'd be able to store in this program as is, but may be something to investigate more or experiment with, as this example in and of itself is experimental and just to give you an understanding of how things work.

Next, we can update the test for this new program:

const assert = require("assert");
const anchor = require("@project-serum/anchor");
const { SystemProgram } = anchor.web3;

describe("Mysolanaapp", () => {
  const provider = anchor.Provider.env();
  anchor.setProvider(provider);
  const program = anchor.workspace.Mysolanaapp;
  it("It initializes the account", async () => {
    const baseAccount = anchor.web3.Keypair.generate();
    await program.rpc.initialize("Hello World", {
      accounts: {
        baseAccount: baseAccount.publicKey,
        user: provider.wallet.publicKey,
        systemProgram: SystemProgram.programId,
      },
      signers: [baseAccount],
    });

    const account = await program.account.baseAccount.fetch(baseAccount.publicKey);
    console.log('Data: ', account.data);
    assert.ok(account.data === "Hello World");
    _baseAccount = baseAccount;

  });

  it("Updates a previously created account", async () => {
    const baseAccount = _baseAccount;

    await program.rpc.update("Some new data", {
      accounts: {
        baseAccount: baseAccount.publicKey,
      },
    });

    const account = await program.account.baseAccount.fetch(baseAccount.publicKey);
    console.log('Updated data: ', account.data)
    assert.ok(account.data === "Some new data");
    console.log('all account data:', account)
    console.log('All data: ', account.dataList);
    assert.ok(account.dataList.length === 2);
  });
});
Enter fullscreen mode Exit fullscreen mode

To test it out:

anchor test
Enter fullscreen mode Exit fullscreen mode

If the test fails, try turning off the validator and then running again.

Next, let's update the client.

/* app/src/App.js */
import './App.css';
import { useState } from 'react';
import { Connection, PublicKey } from '@solana/web3.js';
import { Program, Provider, web3 } from '@project-serum/anchor';
import idl from './idl.json';

import { PhantomWalletAdapter } from '@solana/wallet-adapter-wallets';
import { useWallet, WalletProvider, ConnectionProvider } from '@solana/wallet-adapter-react';
import { WalletModalProvider, WalletMultiButton } from '@solana/wallet-adapter-react-ui';
require('@solana/wallet-adapter-react-ui/styles.css');

const wallets = [ new PhantomWalletAdapter() ]

const { SystemProgram, Keypair } = web3;
const baseAccount = Keypair.generate();
const opts = {
  preflightCommitment: "processed"
}
const programID = new PublicKey(idl.metadata.address);

function App() {
  const [value, setValue] = useState('');
  const [dataList, setDataList] = useState([]);
  const [input, setInput] = useState('');
  const wallet = useWallet()

  async function getProvider() {
    /* create the provider and return it to the caller */
    /* network set to local network for now */
    const network = "http://127.0.0.1:8899";
    const connection = new Connection(network, opts.preflightCommitment);

    const provider = new Provider(
      connection, wallet, opts.preflightCommitment,
    );
    return provider;
  }

  async function initialize() {    
    const provider = await getProvider();
    /* create the program interface combining the idl, program ID, and provider */
    const program = new Program(idl, programID, provider);
    try {
      /* interact with the program via rpc */
      await program.rpc.initialize("Hello World", {
        accounts: {
          baseAccount: baseAccount.publicKey,
          user: provider.wallet.publicKey,
          systemProgram: SystemProgram.programId,
        },
        signers: [baseAccount]
      });

      const account = await program.account.baseAccount.fetch(baseAccount.publicKey);
      console.log('account: ', account);
      setValue(account.data.toString());
      setDataList(account.dataList);
    } catch (err) {
      console.log("Transaction error: ", err);
    }
  }

  async function update() {
    if (!input) return
    const provider = await getProvider();
    const program = new Program(idl, programID, provider);
    await program.rpc.update(input, {
      accounts: {
        baseAccount: baseAccount.publicKey
      }
    });

    const account = await program.account.baseAccount.fetch(baseAccount.publicKey);
    console.log('account: ', account);
    setValue(account.data.toString());
    setDataList(account.dataList);
    setInput('');
  }

  if (!wallet.connected) {
    return (
      <div style={{ display: 'flex', justifyContent: 'center', marginTop:'100px' }}>
        <WalletMultiButton />
      </div>
    )
  } else {
    return (
      <div className="App">
        <div>
          {
            !value && (<button onClick={initialize}>Initialize</button>)
          }

          {
            value ? (
              <div>
                <h2>Current value: {value}</h2>
                <input
                  placeholder="Add new data"
                  onChange={e => setInput(e.target.value)}
                  value={input}
                />
                <button onClick={update}>Add data</button>
              </div>
            ) : (
              <h3>Please Inialize.</h3>
            )
          }
          {
            dataList.map((d, i) => <h4 key={i}>{d}</h4>)
          }
        </div>
      </div>
    );
  }
}

const AppWithProvider = () => (
  <ConnectionProvider endpoint="http://127.0.0.1:8899">
    <WalletProvider wallets={wallets} autoConnect>
      <WalletModalProvider>
        <App />
      </WalletModalProvider>
    </WalletProvider>
  </ConnectionProvider>
)

export default AppWithProvider;    
Enter fullscreen mode Exit fullscreen mode

Next, build and deploy the program (be sure that solana-test-validator is running):

anchor build

anchor deploy
Enter fullscreen mode Exit fullscreen mode

With the new build you'll have a new IDL that you'll need to update for your client. Either copy over the new IDL to app/src/idl.json or run your copyIdl.js script.

Testing it out

When testing out the new program, be sure to update the idl.json file that was created by the build.

Change into the app directory and run the start command:

npm start
Enter fullscreen mode Exit fullscreen mode

Deploying to Devnet

Deploying to a live network is pretty straightforward from here. The main things we need to do are:

1. Update the Solana CLI to use devnet:

solana config set --url devnet
Enter fullscreen mode Exit fullscreen mode

2. Update Phantom wallet to use devnet

3. Open Anchor.toml and update the cluster from localnet to devnet.

4. Rebuild the program. Be sure the program ID in Anchor.toml matches the current program ID.

5. Deploy the program again, this time it will be deployed to devnet

6. In app/src/App.js, we need to also update the network, this time using the clusterApiUrl from @solana/web3, like this:

/* before */
<ConnectionProvider endpoint="http://127.0.0.1:8899">

/* after */
import {
  ...,
  clusterApiUrl
} from '@solana/web3.js';

const network = clusterApiUrl('devnet');

<ConnectionProvider endpoint={network}>
Enter fullscreen mode Exit fullscreen mode

From here, you should be able to deploy and test as we have done the the previous steps.

The code for this project is located here

Next steps

Another in depth tutorial I'd suggest checking out next is Create a Solana dApp from scratch which implements a simplified version of Twitter as a Solana dapp.


If you're interested in working with technology like this full time, come join me and my team at Edge & Node, we're hiring!

Top comments (119)

Collapse
danmt profile image
Daniel Marin

Really nice read,

Just one tiny thing, when using Anchor it's recommended to use useAnchorWallet hook instead of useWallet. Some wallets don't support signing txs, if you provide such a wallet to the Provider constructor you'll get runtime errors.

I guess you're aware of that, just in case somebody has issues.

Collapse
haodev007 profile image
Holmes

Hi, Daniel.

If I use useAnchorWallet instead of useWallet, can I get AnchorError via any solana wallets?
When I have called rpc api from solana program on Frontend, I need to get AnchorError in try-catch cause.
But I can see AnchorError on browser console(via solfare wallet) but I cannot catch the error. Any thoughts?

Thanks! Have a nice day~

Collapse
alfonzomillions profile image
Alfonzo

Great post!

One thing though in the 1st test, you will need to declare the variable "_baseAccount" before you can assign it.

just add "let _baseAccount" in the describe test block.

Also I had to turn off the solana-test-validator for the tests to pass for some reason. Just thought I'd post just incase anyone ran into a similar issue!

Collapse
danmt profile image
Daniel Marin

I believe this happens because Anchor tests spin up a test validator instance. I know somewhere in the Anchor tutorial docs it's explained. Just make sure to turn off the test validator when running the test suite and you should be ready to go.

Collapse
marcinkozuchowski profile image
Marcin Kożuchowski

man, saved my life!

Collapse
breadandwater profile image
Adrian Paniagua Sanchez

You man made my day! Thanks a lot, I was trying to figure out why the tests are getting errors and errors... Adding this line of code and also stopping the solana-test-validator made my test work! Thanks!

Collapse
saxenism profile image
Rahul Saxena

You could also go for anchor test --skip-local-validator

Collapse
mrslappy profile image
mrslappy

Thankyou, this had me fcked for ages

Collapse
3lii06 profile image
Ali ₿

thx for posting appreciate it ran into the same issues XD

Collapse
hypeman profile image
hype • Edited on

If you end up with

Module not found: Error: Can't resolve './adapter' in '/Users/me/Desktop/mysolanaapp/app/node_modules/@solana/wallet-adapter-bitkeep/lib'
Did you mean 'adapter.js'?
BREAKING CHANGE: The request './adapter' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request." 
Enter fullscreen mode Exit fullscreen mode

Error, its probably because of create-react-app using "react-scripts": "5.0.0", in order to fix - downgrade to "react-scripts": "^4.0.3" or do manual webpack hacking
source: giters.com/solana-labs/wallet-adap...
and github.com/reduxjs/redux/issues/4174

Collapse
mcintyre94 profile image
mcintyre94

This Alchemy tutorial is a really good guide to the manual webpack hacking: alchemy.com/blog/how-to-polyfill-n...

You only need these overrides:

Object.assign(fallback, {
    "crypto": require.resolve("crypto-browserify"),
    "stream": require.resolve("stream-browserify"),
  })
Enter fullscreen mode Exit fullscreen mode
Collapse
walkre profile image
walkre • Edited on

I changed "react-scripts": "5.0.0" into "react-scripts": "4.0.3" and I got the following error at Building the React app when I run npm start.
Anyone could help me?

Failed to compile.

./node_modules/@solana/wallet-adapter-base/lib/esm/signer.js 16:16
Module parse failed: Unexpected token (16:16)
File was processed with these loaders:
 * ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|           ...sendOptions
|         } = options;
>         signers?.length && transaction.partialSign(...signers);
|         transaction = await this.signTransaction(transaction);
|         const rawTransaction = transaction.serialize();
Enter fullscreen mode Exit fullscreen mode
Collapse
mengni profile image
How

I followed the dowgrade instruction for all dependencies, but still got the following error:

Failed to compile.

./src/App.js
Attempted import error: 'PhantomWalletAdapter' is not exported from '@solana/wallet-adapter-wallets'.

Could someone help with this? Thanks!

Collapse
jdguzmans profile image
jdguzmans

@walkre I am having the same error, did you solve this?

Thread Thread
walkre profile image
walkre

Sadly, no.

Thread Thread
jdguzmans profile image
jdguzmans

with these dependencies it worked for me
...
"@solana/wallet-adapter-base": "^0.7.1",
"@solana/wallet-adapter-react": "^0.13.1",
"@solana/wallet-adapter-react-ui": "^0.6.1",
"@solana/wallet-adapter-wallets": "^0.11.3",
"@solana/web3.js": "^1.31.0",
...
"react-scripts": "4.0.3",

Thread Thread
walkre profile image
walkre

That worked for me too.
Thank you very much!!!

Collapse
chillnarmadillo profile image
chillnArmadillo

Cheers mate! Made my day.

Collapse
khrysaoar profile image
Khrysaoar • Edited on

This is really nice for developers like me who are new to blockchain apps development.
It's a very informative tutorial!

But I'm currently having trouble at the first Hello World build.
When everything is set and I run npm start inside the mysolanaapp/app folder, I started getting lots of error in regards to the @solana/wallet-adapter-react @solana/wallet-adapter-react-ui @solana/wallet-adapter-wallets @solana/wallet-adapter-base

Example of one error is:
ERROR in ./src/App.js 20:0-16
export 'getPhantomWallet' (imported as 'getPhantomWallet') was not found in '@solana/wallet-adapter-wallets' (module has no exports)

Collapse
khrysaoar profile image
Khrysaoar

I solved this by running npm install inside the mysolanaapp\app before running npm start. Thank you so much!!

Collapse
chillnarmadillo profile image
chillnArmadillo

Awesome tutorial!

Still having the same issue though as described by @khrysaoar.
The npm install did not get the job done for me.

Hints anyone?
Thank you very much!

Thread Thread
chillnarmadillo profile image
chillnArmadillo

Resolved as mentioned by @hypeman.
Changed "react-scripts": "5.0.0" to "react-scripts": "4.0.3"

Thread Thread
0cv profile image
Christophe Vidal

thank you it helped! And then I faced the next error with BitKeepWalletAdapter which could not be imported. The solution was to downgrade the following dependencies:

...
    "@solana/wallet-adapter-base": "^0.7.1",
    "@solana/wallet-adapter-react": "^0.13.1",
    "@solana/wallet-adapter-react-ui": "^0.6.1",
    "@solana/wallet-adapter-wallets": "^0.11.3",
    "@solana/web3.js": "^1.31.0",
...
Enter fullscreen mode Exit fullscreen mode

it feels like Solana tooling is breaking dependencies on a weekly basis :-(

Collapse
khrysaoar profile image
Khrysaoar

@dabit3 Hi, I hope you can help me or someone. Thank you so much!

Collapse
zhbadya profile image
Roman Zhbadynskyi

Very clear tutorial, thanks!
Need some help.
I've follow 'Building Hello World' part and deployed program to localhost cluster.
After frontend calling program.rpc.create method and Phantom wallet approving I recieve

Transaction simulation failed: Error processing Instruction 0: custom program error: 0xa7

Account have enought balance, any suggestions?

Collapse
legendaryphoenixicarus profile image
legendaryphoenixicarus • Edited on

I am also getting this issue. I updated the lib.rs and Anchor.toml files with programID.

Here are the steps I've done.

anchor build
Enter fullscreen mode Exit fullscreen mode

And this returned the programID in the form of public key.

solana address -k target/deploy/example2-keypair.json
>BEPhkwFSf3m5Daz5LZPZhBbeVBkvY3vKnGRiWtNwFn54
Enter fullscreen mode Exit fullscreen mode

Replaced the program id in lib.rs and Anchor.toml

// lib.rs
use anchor_lang::prelude::*;

declare_id!("BEPhkwFSf3m5Daz5LZPZhBbeVBkvY3vKnGRiWtNwFn54");

#[program]
mod example2 {
    use super::*;

... ...
Enter fullscreen mode Exit fullscreen mode
// Anchor.toml
[programs.localnet]
example2 = "BEPhkwFSf3m5Daz5LZPZhBbeVBkvY3vKnGRiWtNwFn54"

[registry]
url = "https://anchor.projectserum.com"

[provider]
cluster = "localnet"
wallet = "~/.config/solana/id.json"

[scripts]
test = "mocha -t 1000000 tests/"
Enter fullscreen mode Exit fullscreen mode
anchor deploy
Enter fullscreen mode Exit fullscreen mode

I already checked the programID I am using in the app, and it matches to above one.

// App.js
  async function initialize() {    
    const provider = await getProvider();
    /* create the program interface combining the idl, program ID, and provider */
    const program = new Program(idl, programID, provider);
    console.log(program.programId.toBase58());
Enter fullscreen mode Exit fullscreen mode

But I am still getting this issue when I am trying to call the initialize() function.

Transaction simulation failed: Error processing Instruction 0: custom program error: 0xa7 
    Program BEPhkwFSf3m5Daz5LZPZhBbeVBkvY3vKnGRiWtNwFn54 invoke [1]
    Program 11111111111111111111111111111111 invoke [2]
    Program 11111111111111111111111111111111 success
    Program log: Custom program error: 0xa7
    Program BEPhkwFSf3m5Daz5LZPZhBbeVBkvY3vKnGRiWtNwFn54 consumed 5512 of 200000 compute units
    Program BEPhkwFSf3m5Daz5LZPZhBbeVBkvY3vKnGRiWtNwFn54 failed: custom program error: 0xa7
Enter fullscreen mode Exit fullscreen mode

I am really not sure why this happens and it's bothering me for days. Please help me if you have any idea.

Collapse
proto133 profile image
Peter Roto

Did you fund the wallet?

Collapse
halimabergaoui profile image
halimabergaoui

Hey, same problem here. did you solve this?

Collapse
zhbadya profile image
Roman Zhbadynskyi

I've carefully checked everything step-by-step and it works. I think my mistake was in

solana address -k target/deploy/mysolanaapp-keypair.json
Enter fullscreen mode Exit fullscreen mode

cause of different app name

Collapse
ebushi profile image
e-武士

Great Tutorial, thanks for posting ... Having a little trouble in a particular spot though.

Not sure why but I'm getting this error whenever I type 'anchor test' or 'anchor deploy' . 👇

'Error: Not a directory (os error 20)'

Does anyone know what this means ?

Collapse
anderbuendia profile image
anderb

I think that you need to install rust. I did that and then it works!. Use the next command in the terminal to do it:

curl --proto '=https' --tlsv1.2 -sSf sh.rustup.rs | sh
source $HOME/.cargo/env
rustup component add rustfmt

Collapse
ntirinigasr profile image
Michael Ntiriniga Michael Senior

Hey, did you solve it I'm encountering the same problem

Collapse
ahmedali profile image
Ahmed Ali

One of the most useful Solana related tutorials. Thank you!
I have couple of questions though:

  • At this point I am getting an AccountNotProgramOwned error which I can understand why, but I don't know how to fix
  • How can we change the program so that it maintains the state between browser sessions? i.e if I close the browser, re-open and connect my wallet, it would restore my last state instead of starting from scratch?
Collapse
egemengol profile image
Egemen Göl

Have you managed to solve the AccountNotProgramOwned error? I seem to stuck on that error as well.

Collapse
thalesbmc profile image
Thales Brederodes

local storage.

Collapse
0cv profile image
Christophe Vidal • Edited on

sounds like a terrible idea for anything beyond a demo. What if the user clears his cookies or use another browser, then he loses his account data and starts from new? I could imagine that a base account could be generated from the public key of the provider/user to have something deterministic which can be safely retrieved and reused

EDIT: the method PublicKey.createWithSeed based on the user address, the program ID and a deterministic storage key that can be hardcoded in the front end app, is actually the solution to this

Thread Thread
thalesbmc profile image
Thales Brederodes

I agree, just for demo purpose. Thanks for sharing the right way.

Collapse
deven96 profile image
Diretnan Domnan

Just the guide I was looking for!

Collapse
biiishal profile image
bishal • Edited on

For anyone coming to this in 2022 with anchor-cli 0.22.1, you want to replace ProgramResult with updated Result<()>

docs.rs/anchor-lang/latest/anchor_...
rather than
docs.rs/anchor-lang/0.18.0/anchor_...

Also, for others who might have a run in with this error message Error: failed to send transaction: Transaction simulation failed: Attempt to load a program that does not exist while running the tests. Check out this github.com/project-serum/anchor/is...

You might want to turn off your solana-test-validator process, delete your node_modules and do a fresh yarn install, and finally try the anchor test. The issue seems to be when the name of a mod is changed the tests fails, which made sense in my case because I was going with a different name for my project (anchor_crud instead of mysolanaapp).

Collapse
quinncuatro profile image
Henry Quinn

In case anyone else was having a problem getting all the base tools set up on Ubuntu, I threw together a shell script to install everything so you can jump straight to writing code!

gist.github.com/Quinncuatro/2ef56e...

Collapse
lunchboxav profile image
Adityo Pratomo

thank you for the guide! just what I'm looking for.

additional info, if anyone is using WSL, to run the test-ledger command succesfully, make sure you're in ~ directory instead of the default mount directory, e.g /mnt/c/Users...

Collapse
josephani profile image
Joseph Ani

Hello all,
I go to the point of running the anchor test and encountered errors, can someone help me out. Thanks

Image description

Collapse
kimchishi profile image
kimchi-shi

Replace it with "Result<()>"

Collapse
josephani profile image
Joseph Ani

Thanks Kimchi-shi, now am encountering the following errors.
Image description

Collapse
rwreynolds profile image
Rick Reynolds

Great tutorial. Got me started from scratch.

On the first test however I am receiving the following error. Any thoughts?

Failed to run test: mocha -t 1000000 tests/: No such file or directory (os error 2)

Collapse
dimfeld profile image
Daniel Imfeld

I ran into this as well, and in my case the problem was that anchor test expects mocha to be installed globally (npm i -g mocha or equivalent), which I forgot to do.

Collapse
rwreynolds profile image
Rick Reynolds

Never mind. It appears to have been an ID10T issue.

Collapse
0_tw1tter profile image
Name

Just for future adventurers,

Was the problem that you hadn't changed directory into example1 or example2?

Thread Thread
koenrad profile image
Koenrad MacBride

I just ran into the same problem and found this post while trying to solve it.

My problem was that I had the npm anchor package installed globally (which I did before I realized that it doesn't work on the M1 mac currently). Uninstalling it fixed the issue. (of course you also need to build anchor for it to work properly on the M1)

npm uninstall -g @project-serum/anchor-cli
Enter fullscreen mode Exit fullscreen mode
Collapse
dangjing9999 profile image
Jing Dang

I have a issue when solana app is created with anchor as following:
anchor --version
Only x86_64 / Linux distributed in NPM package right now.
Trying globally installed anchor.
Failed to get version of global binary: Error: spawnSync anchor ENOENT

Collapse
dabit3 profile image
Nader Dabit Author

Yes, looks like you need to install anchor using Cargo:

cargo install --git https://github.com/project-serum/anchor --tag v0.17.0 anchor-cli --locked
Enter fullscreen mode Exit fullscreen mode
Collapse
nsandomeno profile image
Nicholas Sandomeno

Should one take issue to the first two lines in the output from this comment? Does it indicate the NODE_PATH variable is not set properly @dabit3 ?

Collapse
atkinew0 profile image
Eli

Fantastic to have a working example Solana program to refer to thank you!

Just one issue I ran into deploying my program- the npm module with clusterApiUrl seems to be named @solana/web3.js and leaving off the .js didn't work for me.

Collapse
dabit3 profile image
Nader Dabit Author

Hey, thanks Eli, just updated to fix this!! Thank you for the heads up.

Collapse
mrslappy profile image
mrslappy • Edited on

Hey there, thanks for your guide

I seem to be having an issue running the tests from the hello world project. Whenever I run anchor test I get the following error:

Transaction simulation failed: Attempt to load a program that does not exist

anchor.workspace is an empty object when running the test.

Hoping you can help me solve this as I cannot find anything about this anywhere

Collapse
girrihere profile image
Girri Palaniyapan
  1. When running the test, check the programID on the CLI.
  2. Fill that programID inside lib.rs: declare_id!("INSERT_PROGRAM_ID");
  3. Fill that programID inside the anchor.toml file as well.

This fixed the bug for me

Collapse
heaversm profile image
Mike Heavers

How do you check the programID on the CLI?

Collapse
kunkka0822 profile image
Kunkka0822

Hello.

In my experience, you should deploy program before testing. Please run "anchor deploy" before "anchor test".
When deploying, you should set program id. I hope my experience help you. Happy coding!

Collapse
franciscogmm profile image
Francisco Mendoza

I keep on getting this for the hello world app. I'm a bit stuck tbh.

1) mysolanaapp
Creates a counter):
Error: 101: Fallback functions are not supported
at Function.parse (node_modules/@project-serum/anchor/dist/cjs/error.js:40:20)
at Object.rpc as create
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Context. (tests/mysolanaapp.js:13:5)

Collapse
franciscogmm profile image
Francisco Mendoza

nvm! i tried turning off the test validator and it succeeded :)

Collapse
yushoo profile image
kique

This is because anchor test runs the local ledger as well right? Just ran into this issue lol.

Collapse
fred227 profile image
Frédéric Lesage

hi, CAPITAL letters are not supported for function name in your rust on-chain program.
I get the same error when I use some.

Collapse
waglik profile image
waglik

Is it possible for base account not to be generated each time? I wanted to use key/pair that I used for deploying the contract but it failed. What is the right way to do it if I want to persist data for the users?

Collapse
johnamcconnell profile image
CHIΞFMCCONNΞLL.ΞTH

I think there is a link in the article to make it happen but here is a possible solution.

In the src directory just make a file called createKeyPair.js and add this code:

// Shoutout to Nader Dabit for helping w/ this!
// twitter.com/dabit3

const fs = require('fs')
const anchor = require("@project-serum/anchor")

const account = anchor.web3.Keypair.generate()

fs.writeFileSync('./keypair.json', JSON.stringify(account))

Then inside your app run:
node createKeyPair.js
which should create a keypair.json (which is what holds the keypair for persistence)

Then in the App.js import the json file
import kp from './keypair.json'

and then whereever in your App.js you are calling:
let baseAccount = Keypair.generate();

Just replace with the following:

const arr = Object.values(kp._keypair.secretKey)
const secret = new Uint8Array(arr)
const baseAccount = web3.Keypair.fromSecretKey(secret)

That should be it. now it should be persistent on loading for anyone connected to your app.

Collapse
fred227 profile image
Frédéric Lesage

hi nader, I just wanted to say thank you for your work as it was a great source of inspiration for me.
I ve made my best to test solana :
dev.to/fred227/thewheel-a-first-ex...
Of course your great article is mentioned in my article.
thanks a lot.
frédéric

Collapse
jchs profile image
jchs

At the end of part 1, the app.js generates the following error for me:

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app See reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

Not sure what is the issue here...
if I do npm ls react:

futureoffrance@ /mnt/c/Users/unkn0wn/solana/futureoffrance
├─┬ @solana/wallet-adapter-react-ui@0.6.1
│ ├─┬ react-dom@17.0.2
│ │ └── react@17.0.2 deduped
│ └── react@17.0.2
└─┬ @solana/wallet-adapter-react@0.13.1
└── react@17.0.2 deduped

So I see I have react 2 times, but isn't that normal? It's from different modules. I couldn't remove just one there I think...

Any help appreciated
Thank you

Collapse
merlox profile image
merlox

you're probaby using useWallet or useState outside of a functional component. Make sure they are inside

Collapse
jackrobsonalpha profile image
Jack Robson

Does anybody know if it is possible to sign an Anchor transaction with a Phantom wallet?

the example signs using the baseAccount keypair

but when using Phantom, we don't have the keypair, we sign the transactions...

Any thoughts?

Collapse
magnum6actual profile image
magnum6actual

Learning anchor and getting it going just by following patterns. I don't fully understand what's going on underneath, though. For example, what is 'info when creating structs? In this line:

pub struct Create<'info>

I'm assuming 'info is pointing to some Anchor struct definition - but unsure which because it appears pretty much everywhere regardless of what's being created. Or here:

pub base_account: Account<'info, BaseAccount>

Same question - and are we overloading with the fields from BaseAccount as well? Trying to learn rust & anchor at the same time, so not sure if this is an anchor question or rust question.

Collapse
magnum6actual profile image
magnum6actual

To answer my own question, 'info is a rust parameter for managing lifetime of references. The single quote is the operator and "info" is just a variable name (could be anything). All references tagged with 'info must be active until all are complete. More here: blog.logrocket.com/understanding-l...

Collapse
malai_23 profile image
M.Malai

I am at the react stage. However I have some issues when I click on the create counter function. This is the error I get: index.js:1 Transaction simulation failed: Attempt to load a program that does not exist

Collapse
kunkka0822 profile image
Kunkka0822

Hello.

In my experience, you should deploy program before testing. Please run "anchor deploy" before "anchor test".
When deploying, you should set program id. I hope my experience help you. Happy coding!

Collapse
thanhvk profile image
thanhvk

It's very helpful.
I hope you will write a guide about NFT in the future.

Collapse
0xdjole profile image
Djole

This is exactly what I am looking for right now :D

Collapse
merlox profile image
merlox

I'm gonna write one if you guys want

Collapse
cryptodogg profile image
CryptoDogg

Thank you for great post.

When I set the network to devnet,
const network = clusterApiUrl('devnet');
I got the error;
Transaction simulation failed: This account may not be used to pay transaction fees.

Could anyone help?

Collapse
krishnapsftware profile image
Krishna-Psftware

Even i was facing the same issue, but I hardcoded the devnet url.

Collapse
tabishauthornate profile image
Tabish-Authornate

hardcoding the devnet solved the issue?

Thread Thread
krishnapsftware profile image
Krishna-Psftware

yes.it got resolved. But this tutorial is very helpful.

Thanks for the Nader

Collapse
superjose profile image
Jose

It just popped up inside Chrome's Feed in my phone and I've been enjoying to read this a lot.

Thank you so much for taking the time to write this. Rust is a big challenge to learn, and Solana docs aren't as clear as one may like. There's lot of back and forth reading as the solana 101 article you've linked.

I wanted to ask for anyone who can answer me, from the following paragraph:

"validators use Not Bittorrent to fetch blocks and dont need to wait for all the pieces to presume correctness. they also claim to offload data to Not Filecoin so validators can run light clients but someone in their discord told me they never implemented that so idk"

What does the author mean by "Not BitTorrent" and "Not Filecoin". I know both, but I don't get to which protocol or service he's referring to. Google hasn't helped, either.

Collapse
krishnapsftware profile image
Krishna-Psftware

Hi Everyone,

I have a doubt is there any chance to create a solana api for invoking this api into frontend application which is built on reactjs. Can any one help me, how to make this solana api .

Collapse
heaversm profile image
Mike Heavers

Typo:

it("Creates a counter)", async () => {

should be:

it("Creates a counter", async () => {

Collapse
raduc4 profile image
Raduc4